home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Science / RasMol2 / command.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-28  |  70.8 KB  |  2,936 lines  |  [TEXT/KAHL]

  1. /* command.c
  2.  * RasMol2 Molecular Graphics
  3.  * Roger Sayle, October 1994
  4.  * Version 2.5
  5.  */
  6. #include "rasmol.h"
  7.  
  8. #ifdef IBMPC
  9. #include <windows.h>
  10. #include <malloc.h>
  11. #endif
  12. #ifdef APPLEMAC
  13. #ifdef __CONDITIONALMACROS__
  14. #include <Printing.h>
  15. #else
  16. #include <PrintTraps.h>
  17. #endif
  18. #include <Types.h>
  19. #endif
  20. #ifndef sun386
  21. #include <stdlib.h>
  22. #endif
  23.  
  24. #include <ctype.h>
  25. #include <stdio.h>
  26.  
  27. #if !defined(IBMPC) && !defined(VMS) && !defined(APPLEMAC)
  28. #include <pwd.h>
  29. #endif
  30.  
  31. #define COMMAND
  32. #include "command.h"
  33. #include "tokens.h"
  34. #include "molecule.h"
  35. #include "abstree.h"
  36. #include "transfor.h"
  37. #include "render.h"
  38. #include "graphics.h"
  39. #include "pixutils.h"
  40. #include "outfile.h"
  41. #include "script.h"
  42.  
  43.  
  44. /* Macros for commonly used loops */
  45. #define ForEachAtom  for(chain=Database->clist;chain;chain=chain->cnext) \
  46.              for(group=chain->glist;group;group=group->gnext)    \
  47.              for(ptr=group->alist;ptr;ptr=ptr->anext)
  48. #define ForEachBond  for(bptr=Database->blist;bptr;bptr=bptr->bnext)
  49.  
  50.  
  51. #define IsIdentChar(x)  ((isalnum(x))||((x)=='_')||((x)=='$'))
  52.  
  53.  
  54. #ifndef VMS
  55. #ifdef IBMPC
  56. #define DirChar  '\\'
  57. #else
  58. #define DirChar  '/'
  59. #endif
  60. #endif
  61.  
  62.  
  63. #define ErrSyntax        0
  64. #define ErrBigNum        1
  65. #define ErrBadOpt        2
  66. #define ErrParam         3
  67. #define ErrFilNam        4
  68. #define ErrBadLoad       5
  69. #define ErrNotNum        6
  70. #define ErrNotSep        7
  71. #define ErrNotBrac       8
  72. #define ErrNoCol         9
  73. #define ErrColour       10
  74. #define ErrBadArg       11
  75. #define ErrBadExpr      12
  76. #define ErrParen        13
  77. #define ErrScript       14
  78. #define ErrFunc         15
  79. #define ErrSetName      16
  80. #define ErrBadSet       17
  81. #define ErrInScrpt      18
  82.  
  83.  
  84. static char *ErrorMsg[] = {
  85.     "Invalid command syntax",            /* ErrSyntax  */
  86.     "Parameter value too large",         /* ErrBigNum  */
  87.     "Invalid parameter setting",         /* ErrBadOpt  */
  88.     "Invalid parameter name",            /* ErrParam   */
  89.     "Filename string expected",          /* ErrFilNam  */
  90.     "Molecule database loaded",          /* ErrBadLoad */
  91.     "Integer value expected",            /* ErrNotNum  */
  92.     "Comma separator missing",           /* ErrNotSep  */
  93.     "Close bracket ']' expected",        /* ErrNotBrac */
  94.     "No colour specified",               /* ErrNoCol   */
  95.     "Unknown or incorrect colour",       /* ErrColour  */
  96.     "Invalid command argument",          /* ErrBadArg  */
  97.     "Syntax error in expression",        /* ErrBadExpr */
  98.     "Close parenthesis ')' expected",    /* ErrParen   */
  99.     "Script command stack too deep",     /* ErrScript  */
  100.     "Open parenthesis '(' expected",     /* ErrFunc    */
  101.     "Invalid or missing atom set name",  /* ErrSetName */
  102.     "Not enough memory to define set",   /* ErrBadSet  */
  103.     "Disabled command in script file"    /* ErrInScrpt */
  104.     };
  105.  
  106.  
  107. typedef struct _HlpEntry {
  108.         struct _HlpEntry __far *next;
  109.         struct _HlpEntry __far *info;
  110.         char __far *keyword;
  111.         Long fpos;
  112.         } HlpEntry;
  113.  
  114. #define HelpPool   16
  115. static char *HelpFileName;
  116. static char HelpFileBuf[80];
  117. static HlpEntry __far *FreeInfo;
  118. static HlpEntry __far *HelpInfo;
  119.  
  120.  
  121. #define STACKSIZE  10
  122. static char *NameStack[STACKSIZE];
  123. static int LineStack[STACKSIZE];
  124.  
  125. #define HISTSIZE    4096
  126. #define HISTMASK    4095
  127. static char HistBuff[HISTSIZE];
  128. static int MinHist,MaxHist;
  129. static int CurHist;
  130.  
  131. static char *CurPrompt;
  132. static int CurPos,MaxPos;
  133. static int FileDepth;
  134.  
  135. static int TokenLength;
  136. static Long TokenValue;
  137. static char TokenIdent[128];
  138. static char *TokenStart;
  139. static char *TokenPtr;
  140. static int CurToken;
  141.  
  142.  
  143. static int RVal, GVal, BVal;
  144.  
  145. #ifdef FUNCPROTO
  146. /* Forward Declarations */
  147. int ExecuteCommand();
  148. int ProcessLine();
  149. int ExecuteIPCCommand( char __huge* );
  150. #endif
  151.  
  152.  
  153.  
  154. static void UpdateLine()
  155. {
  156.     register int i;
  157.  
  158.     for( i=CurPos; i<MaxPos; i++ )
  159.     WriteChar(CurLine[i]);
  160.     WriteChar(' ');
  161.     for( i=MaxPos+1; i>CurPos; i-- )
  162.     WriteChar(0x08);
  163. }
  164.  
  165. static void CopyHistory()
  166. {
  167.     register int i;
  168.  
  169.     for( i=CurPos; i>0; i-- )
  170.     WriteChar(0x08);
  171.     for( i=0; i<MaxPos; i++ )
  172.     WriteChar(' ');
  173.     WriteChar(0x0D);
  174.     WriteString(CurPrompt);
  175.  
  176.     CurPos = 0;
  177.     if( (i=CurHist) != MaxHist )
  178.     while( HistBuff[i] )
  179.     {   CurLine[CurPos++] = HistBuff[i];
  180.         WriteChar(HistBuff[i]);
  181.         i = (i+1) & HISTMASK;
  182.     }
  183.     CurLine[CurPos] = 0;
  184.     MaxPos = CurPos;
  185. }
  186.  
  187.  
  188. int ProcessCharacter( ch )
  189.     int ch;
  190. {
  191.     register int i;
  192.  
  193.     if( !ch ) return( False );
  194.     if( (ch>=' ') && (ch<='~') )
  195.     {   if( MaxPos<MAXLINELEN )
  196.     {   for( i=MaxPos; i>CurPos; i-- )
  197.         CurLine[i] = CurLine[i-1];
  198.         CurLine[CurPos++] = ch;
  199.         CurLine[++MaxPos] = 0;
  200.  
  201.         WriteChar(ch);
  202.         if( CurPos<MaxPos )
  203.         UpdateLine();
  204.     } else 
  205.         WriteChar(0x07);
  206.     
  207.     } else
  208.     switch( ch )
  209.     {    case( 0x7f ):  /* DEL and ^H */
  210.          case( 0x08 ):  if( CurPos>0 )
  211.                 {   for( i=CurPos; i<=MaxPos; i++ )
  212.                     CurLine[i-1] = CurLine[i];
  213.                 CurPos--; MaxPos--;
  214.                 WriteChar(0x08);
  215.                 UpdateLine();
  216.                 }
  217.                 break;
  218.  
  219.          case( 0x04 ):  if( CurPos<MaxPos ) /* ^D */
  220.                 {   for( i=CurPos; i<MaxPos; i++ )
  221.                     CurLine[i] = CurLine[i+1];
  222.                 MaxPos--; UpdateLine();
  223.                 }
  224.                 break;
  225.  
  226.          case( 0x0d ):  /* ^M and ^J */
  227.          case( 0x0a ):  WriteChar('\n');
  228.                 if( MaxPos )
  229.                 for( i=0; i<=MaxPos; i++ )
  230.                 {    HistBuff[MaxHist] = CurLine[i];
  231.                      MaxHist=(MaxHist+1)&HISTMASK;
  232.                      if( MaxHist==MinHist )
  233.                      {   while( HistBuff[MinHist] )
  234.                          MinHist=(MinHist+1)&HISTMASK;
  235.                      MinHist=(MinHist+1)&HISTMASK;
  236.                      }
  237.                 }
  238.                 CommandActive = False;
  239.                 return( True );
  240.                 break;
  241.  
  242.          case( 0x02 ):  if( CurPos>0 )  /* ^B */
  243.                 {    WriteChar(0x08);
  244.                  CurPos--;
  245.                 }
  246.                 break;
  247.  
  248.          case( 0x06 ):  if( CurPos<MaxPos )  /* ^F */
  249.                 WriteChar(CurLine[CurPos++]);
  250.                 break;
  251.  
  252.          case( 0x01 ):  while( CurPos>0 )   /* ^A */
  253.                 {    WriteChar(0x08);
  254.                  CurPos--;
  255.                 }
  256.                 break;
  257.  
  258.          case( 0x05 ):  while( CurPos<MaxPos )  /* ^E */
  259.                 WriteChar(CurLine[CurPos++]);
  260.                 break;
  261.  
  262.          case( 0x0c ):  WriteChar('\n');    /* ^L */
  263.                 WriteString(CurPrompt);
  264.                 for( i=0; i<MaxPos; i++ )
  265.                 WriteChar(CurLine[i]);
  266.                 for( i=CurPos; i<MaxPos; i++ )
  267.                 WriteChar(0x08);
  268.                 break;
  269.  
  270.          case( 0x10 ):  if( CurHist != MinHist ) /* ^P */
  271.                 {   CurHist -= 2;
  272.                 if( CurHist<0 )
  273.                     CurHist += HISTSIZE;
  274.                 while( HistBuff[CurHist] )
  275.                     CurHist=CurHist?CurHist-1:HISTMASK;
  276.                 CurHist = (CurHist+1)&HISTMASK;
  277.                 CopyHistory();
  278.                 }
  279.                 break;
  280.  
  281.          case( 0x0e ):  if( CurHist != MaxHist ) /* ^N */
  282.                 {   while( HistBuff[CurHist] )
  283.                     CurHist = (CurHist+1)&HISTMASK;
  284.                 CurHist = (CurHist+1)&HISTMASK;
  285.                 CopyHistory();
  286.                 }
  287.                 break;
  288.     }
  289.     return( False );
  290. }
  291.  
  292.  
  293. void ResetCommandLine( state )
  294.      int state;
  295. {
  296.     if( state )
  297.     {   EnableMenus(state==1);
  298.     switch( CurState=state )
  299.     {   case(1):   CurPrompt="RasMol> ";            break;
  300.         case(2):   CurPrompt="PDB file name:";      break;
  301.         case(3):   CurPrompt="Image file name:";    break;
  302.         case(4):   CurPrompt="Molecule file name:"; break;
  303.     }
  304.     }
  305.  
  306.     if( CommandActive )
  307.     WriteChar('\n');
  308.     CommandActive = True;
  309.     WriteString(CurPrompt);
  310.  
  311.     CurHist = MaxHist;
  312.     CurPos = MaxPos = 0;
  313.     CurLine[0] = 0;
  314. }
  315.  
  316.  
  317.  
  318. static void CommandError( error )
  319.     register char *error;
  320. {
  321.     register char *ptr;
  322.     char buffer[40];
  323.  
  324.     if( TokenPtr )
  325.     {   if( FileDepth > -1 )
  326.     {   if( CommandActive )
  327.         WriteChar('\n');
  328.         CommandActive=False;
  329.         
  330.         WriteString(CurLine);
  331.         WriteChar('\n');
  332.     } else WriteString("        ");
  333.  
  334.     for( ptr=CurLine; ptr<TokenStart; ptr++ )
  335.         WriteChar(' ');
  336.     WriteString("^\n");
  337.     }
  338.  
  339.     if( FileDepth > -1 )
  340.     {   if( LineStack[FileDepth] )
  341.     {   if( NameStack[FileDepth] )
  342.         {   WriteChar('"');
  343.         WriteString(NameStack[FileDepth]);
  344.         WriteString("\",");
  345.         }
  346.         sprintf(buffer,"line %d: ",LineStack[FileDepth]);
  347.         WriteString(buffer);
  348.     } else
  349.     {   WriteString(NameStack[FileDepth]);
  350.         WriteString(": ");
  351.     }
  352.     }
  353.  
  354.     if( error )
  355.     {   WriteString(error);
  356.     WriteString("!\n");
  357.     }
  358.     CommandActive = False;
  359.     CurToken = 0;
  360. }
  361.  
  362.  
  363. static char *ProcessFileName( name )
  364.     char *name;
  365. {
  366. #if !defined(IBMPC) && !defined(VMS) && !defined(APPLEMAC)
  367.     register struct passwd *entry;
  368.     register char *temp;
  369.     char username[64];
  370. #endif
  371.     register char *ptr;
  372.  
  373.  
  374.     while( *name==' ' )
  375.     name++;
  376.  
  377. #if defined(IBMPC) || defined(VMS)
  378.     ptr = DataFileName;
  379.     while( *name && (*name!=' ') )
  380.     {   *ptr++ = ToUpper(*name);
  381.     name++;
  382.     }
  383. #else
  384. #ifdef APPLEMAC
  385.     ptr = DataFileName;
  386.     while( *name )
  387.     *ptr++ = *name++;
  388.  
  389. #else /* UNIX */
  390.     /* Perform filename globbing */
  391.     if( *name=='~' )
  392.     {   ptr = username;  name++;
  393.     while( *name && (*name!=' ') && (*name!='/') )
  394.         *ptr++ = *name++;
  395.     *ptr = '\0';
  396.  
  397.     ptr = DataFileName;
  398.     if( *username )
  399.     {   if( entry=getpwnam(username) )
  400.         {   temp = entry->pw_dir;
  401.         endpwent();
  402.         } else /* Unknown user! */
  403.         {   temp = username;
  404.         *ptr++ = '~';
  405.         }
  406.  
  407.     } else if( !(temp=(char*)getenv("HOME")) )
  408.         temp = ".";
  409.  
  410.     while( *temp )
  411.         *ptr++ = *temp++;
  412.     } else ptr = DataFileName;
  413.  
  414.     while( *name && (*name!=' ') )
  415.     *ptr++ = *name++;
  416. #endif
  417. #endif
  418.     *ptr = '\0';
  419.     return ptr;
  420. }
  421.  
  422.  
  423. /* Filename extensions! */
  424. #define MaxFileExt  4
  425. static char *FileExt[] = { "", ".Z", ".gz", ".z" };
  426.  
  427. static FILE *OpenDataFile( begin, end )
  428.     char *begin, *end;
  429. {
  430.     register FILE *fp;
  431. #if !defined(IBMPC) && !defined(APPLEMAC) && !defined(VMS)
  432.     register char *src, *dst;
  433.     register int i;
  434.     
  435.     for( i=0; i<MaxFileExt; i++ )
  436.     {   dst = end; src = FileExt[i];
  437.     while( *dst++ = *src++ );
  438.     if( fp=fopen(begin,"r") )
  439.         break;
  440.     }
  441. #else
  442.     fp = fopen(begin,"r");
  443. #endif
  444.     *end = '\0';
  445.     return fp;
  446. }
  447.  
  448.  
  449. int FetchFile( format, info, name )
  450.     int format, info;
  451.     char *name;
  452. {
  453. #ifndef APPLEMAC
  454. #if !defined(IBMPC) && !defined(VMS)
  455.     register int ch, comp;
  456. #endif /* UNIX */
  457.     register char *src,*dst;
  458.     char buffer[128];
  459. #endif /* APPLEMAC */
  460.  
  461.     register int done;
  462.     register FILE *fp;
  463.  
  464.     DataFileFormat = 0;
  465.     name = ProcessFileName(name);
  466.     fp = OpenDataFile(DataFileName,name);
  467.  
  468. #ifndef APPLEMAC
  469.     /* Try using a default file path! */
  470.     if( !fp )
  471.     {   switch( format )
  472.     {   case(FormatMol2):    src = (char*)getenv("RASMOLMOL2PATH"); break;
  473.         case(FormatAlchemy): src = (char*)getenv("RASMOLMOLPATH");  break;
  474.         case(FormatMDL):     src = (char*)getenv("RASMOLMDLPATH");  break;
  475.         case(FormatPDB):     src = (char*)getenv("RASMOLPDBPATH");  break;
  476.         case(FormatXYZ):     src = (char*)getenv("RASMOLXYZPATH");  break;
  477.         default:             src = NULL;
  478.     }
  479.  
  480.     if( src && *src )
  481.     {   dst = buffer;
  482.         while( *src ) *dst++ = *src++;
  483. #ifndef VMS
  484.         if( *(dst-1) != DirChar )
  485.         *dst++ = DirChar;
  486. #endif
  487.  
  488.         src = DataFileName;
  489.         while( *dst = *src++ )
  490. #ifndef VMS
  491.         if( *dst == DirChar )
  492.         {   break;
  493.         } else dst++;
  494. #else
  495.         dst++;
  496. #endif
  497.  
  498.         if( !(*dst) && (fp=OpenDataFile(buffer,dst)) )
  499.         {   dst = DataFileName;  src=buffer;
  500.         while( *dst++ = *src++ );
  501.         }
  502.     }
  503.     }
  504. #endif /* APPLEMAC */
  505.  
  506.  
  507.     if( !fp )
  508.     {   *name = '\0';
  509.     if( CommandActive )
  510.         WriteChar('\n');
  511.     WriteString("Error: File '");
  512.     WriteString(DataFileName);
  513.     WriteString("' not found!\n\n");
  514.     CommandActive=False;
  515.     return( False );
  516.     }
  517.  
  518. #if !defined(IBMPC) && !defined(VMS) && !defined(APPLEMAC)
  519.     done = getc(fp);
  520.     if( done == 0x1f )
  521.     {   done = getc(fp);
  522.     fclose(fp);
  523.  
  524.     if( done == 0x9d )
  525.     {   sprintf(buffer,"uncompress -c %s 2> /dev/null\n",DataFileName);
  526.     } else if( done == 0x8b )
  527.     {   sprintf(buffer,"gzip -cdq %s 2> /dev/null\n",DataFileName);
  528.     } else /* bad magic number! */
  529.     {   if( CommandActive )
  530.         WriteChar('\n');
  531.         WriteString("Error: Unrecognised compression format!\n\n");
  532.         CommandActive=False;
  533.         return( False );
  534.     }
  535.    
  536.     comp = True;
  537.     if( !(fp=popen(buffer,"r")) )
  538.     {   if( CommandActive )
  539.         WriteChar('\n');
  540.         WriteString("Error: Unable to decompress file!\n\n");
  541.         CommandActive=False;
  542.         return( False );
  543.     }
  544.     } else /* Uncompressed! */
  545.     {   ungetc(done,fp);
  546.     comp = False;
  547.     }
  548. #endif
  549.  
  550.     done = False;
  551.     switch( format )
  552.     {   case(FormatAlchemy): done = LoadAlchemyMolecule(fp); break;
  553.     case(FormatCharmm):  done = LoadCharmmMolecule(fp);  break;
  554.     case(FormatMol2):    done = LoadMol2Molecule(fp);    break;
  555.     case(FormatPDB):     done = LoadPDBMolecule(fp);     break;
  556.     case(FormatMDL):     done = LoadMDLMolecule(fp);     break;
  557.     case(FormatXYZ):     done = LoadXYZMolecule(fp);     break;
  558.     }
  559.  
  560. #if !defined(IBMPC) && !defined(VMS) && !defined(APPLEMAC)
  561.     if( comp )
  562.     {   if( pclose(fp) )
  563.     {   if( CommandActive )
  564.         WriteChar('\n');
  565.         WriteString("Error: Unable to decompress file!\n\n");
  566.         CommandActive=False;
  567.         return(False);
  568.     }
  569.     } else fclose(fp);
  570. #else /* !defined(UNIX) */
  571.     fclose(fp);
  572. #endif
  573.  
  574.     if( !done ) 
  575.     {   return( False );
  576.     } else if( !Database ) 
  577.     return( True );
  578.  
  579.     if( info )
  580.     DescribeMolecule();
  581.     DataFileFormat = format;
  582.     AdviseUpdate(AdvName);
  583.     AdviseUpdate(AdvClass);
  584.     AdviseUpdate(AdvIdent);
  585.  
  586. #if !defined(IBMPC) && !defined(APPLEMAC)        
  587.     if( Interactive ) 
  588.        FetchEvent(False);
  589. #endif
  590.  
  591.     ReDrawFlag |= RFInitial;
  592.     if( InfoBondCount<=MainAtomCount )
  593.     {   if( MainAtomCount+HetaAtomCount > 255 )
  594.         {   CreateMoleculeBonds(info,False);
  595.         } else CreateMoleculeBonds(info,True);
  596.     }
  597.     InitialTransform();
  598.  
  599.     VoxelsClean = False;
  600.     ApplyTransform();
  601.     return( True );
  602. }
  603.  
  604.  
  605. void LoadScriptFile( fileptr, name )
  606.     FILE *fileptr;
  607.     char *name;
  608. {
  609.     register char *ptr;
  610.     register int ch,len;
  611.  
  612.     if( fileptr )
  613.     {   len = 1;
  614.     for( ptr=name; *ptr; ptr++ )
  615.         len++;
  616.  
  617.     FileDepth++;
  618.     ptr = (char*)malloc( len );
  619.     NameStack[FileDepth] = ptr;
  620.     while( *ptr++ = *name++ );
  621.     LineStack[FileDepth] = 0;
  622.  
  623.     do {
  624.         len = 0;
  625.         ch = getc(fileptr);
  626.         while( (ch!='\n') && (ch!=EOF) )
  627.         {   if( len<MAXBUFFLEN )
  628.             CurLine[len++] = ch;
  629.         ch = getc(fileptr);
  630.         }
  631.  
  632.         LineStack[FileDepth]++;
  633.         if( len<MAXBUFFLEN )
  634.         {   CurLine[len] = '\0';
  635.         if( ExecuteCommand() )
  636.             break;
  637.         } else CommandError("Script command line too long");
  638.     } while( ch!=EOF );
  639.     free(NameStack[FileDepth]);
  640.     fclose( fileptr );
  641.     FileDepth--;
  642.     } else
  643.     {   CommandError( (char*)NULL );
  644.     WriteString("Cannot open script file '");
  645.     WriteString(name);  WriteString("'\n");
  646.     }
  647. }
  648.  
  649. #ifdef FUNCPROTO
  650. /* Function Prototypes */
  651. static int PrefixString( char __far*, char __far* );
  652. #endif
  653.  
  654.  
  655. static int PrefixString( str1, str2 )
  656.     register char __far *str1, __far *str2;
  657. {
  658.     while( *str1 == *str2++ )
  659.     if( *str1++ == '\0' )
  660.         return( True );
  661.     return( *str1 == '\0' );
  662. }
  663.  
  664.  
  665. static HlpEntry __far *EnterHelpInfo( text )
  666.     register char *text;
  667. {
  668.     register HlpEntry __far * __far *tmp;
  669.     register HlpEntry __far *ptr;
  670.     register int res,len,i;
  671.     register char ch;
  672.  
  673.     char keyword[32];
  674.  
  675.     ptr = (void __far*)0;
  676.     while( *text && (*text!='\n') )
  677.     {   while( *text && (*text!='\n') && (*text==' ') )
  678.         text++;
  679.  
  680.     len = 0;
  681.     while( *text && (*text!='\n') && (*text!=' ') )
  682.         if( len<31 )
  683.         {   ch = *text++;
  684.         keyword[len++] = ToUpper(ch);
  685.         } else text++;
  686.     keyword[len]='\0';
  687.  
  688.     if( ptr )
  689.     {   tmp = &ptr->info;
  690.         ptr = (void __far*)0;
  691.     } else tmp = &HelpInfo;
  692.  
  693.     while( *tmp )
  694.     {   res = _fstrcmp(keyword,(*tmp)->keyword);
  695.         if( res==0 ) /* Exact Match */
  696.         {   ptr = *tmp;
  697.         break;
  698.         } else if( res<0 )
  699.         break;
  700.         tmp = &(*tmp)->next;
  701.     }
  702.  
  703.     if( !ptr )
  704.     {   if( !FreeInfo )
  705.         {   ptr = (HlpEntry __far*)_fmalloc(HelpPool*sizeof(HlpEntry));
  706.         if( !ptr ) 
  707.             RasMolFatalExit("Command Error: Insufficient memory!");
  708.         for( i=1; i<HelpPool; i++ )
  709.         {   ptr->next = FreeInfo;
  710.             FreeInfo = ptr++;
  711.         }
  712.         } else
  713.         {   ptr = FreeInfo;
  714.         FreeInfo = ptr->next;
  715.         }
  716.  
  717.         ptr->keyword = (char __far*)_fmalloc(len+1);
  718.         for( i=0; i<=len; i++ )
  719.         ptr->keyword[i] = keyword[i];
  720.  
  721.         ptr->info = (void __far*)0;
  722.         ptr->next = *tmp;
  723.         ptr->fpos = 0;
  724.         *tmp = ptr;
  725.     }
  726.     }
  727.     return( ptr );
  728. }
  729.  
  730. static void InitHelpFile()
  731. {
  732.     register char *src,*dst;
  733.     register HlpEntry __far *fix;
  734.     register HlpEntry __far *ptr;
  735.     register FILE *fp;
  736.     register Long pos;
  737.  
  738.     char buffer[82];
  739.  
  740.  
  741.     HelpFileName = "rasmol.hlp";
  742.     fp=fopen(HelpFileName,"r");
  743.  
  744.     if( !fp && (src=(char*)getenv("RASMOLPATH")) )
  745.     {   HelpFileName = dst = HelpFileBuf; 
  746.     while( *src )
  747.         *dst++ = *src++;
  748. #ifndef VMS
  749.     if( (dst!=HelpFileBuf) && (*(dst-1)!=DirChar) )
  750.         *dst++ = DirChar;
  751. #endif
  752.  
  753.     src = "rasmol.hlp"; 
  754.     while( *dst++ = *src++ );
  755.     fp = fopen(HelpFileName,"r");
  756.     }
  757.  
  758. #ifdef RASMOLDIR
  759.     if( !fp )
  760.     {   src = RASMOLDIR;
  761.     HelpFileName = dst = HelpFileBuf;
  762.     while( *src )
  763.         *dst++ = *src++;
  764. #ifndef VMS
  765.     if( (dst!=HelpFileBuf) && (*(dst-1)!=DirChar) )
  766.         *dst++ = DirChar;
  767. #endif
  768.  
  769.     src = "rasmol.hlp"; 
  770.     while( *dst++ = *src++ );
  771.     fp = fopen(HelpFileName,"r");
  772.     }
  773. #endif
  774.  
  775.     if( !fp )
  776.     {   if( CommandActive )
  777.         WriteChar('\n');
  778.     CommandActive = False;
  779.     
  780.     WriteString("Unable to find RasMol help file!\n");
  781.     HelpFileName = NULL;
  782.     return;
  783.     }
  784.  
  785.     pos = 0;
  786.     fgets(buffer,80,fp);
  787.     while( !feof(fp) )
  788.     {    fix = (void __far*)0;
  789.      while( *buffer=='?' )
  790.      {   if( ptr = EnterHelpInfo(buffer+1) )
  791.          {   ptr->info = fix;
  792.          fix = ptr;
  793.          }
  794.  
  795.          pos = ftell(fp);
  796.          if( !fgets(buffer,80,fp) )
  797.          break;
  798.      }
  799.  
  800.      while( fix )
  801.      {   ptr = fix->info;
  802.          fix->info = (void __far*)0;
  803.          fix->fpos = pos;
  804.          fix = ptr;
  805.      }
  806.  
  807.      while( fgets(buffer,80,fp) )
  808.          if( *buffer=='?' )
  809.          break;
  810.     }
  811.     fclose(fp);
  812. }
  813.  
  814. static void FindHelpInfo()
  815. {
  816.     register HlpEntry __far * __far *tmp;
  817.     register HlpEntry __far *ptr;
  818.     register int res,len;
  819.     register Long pos;
  820.     register FILE *fp;
  821.     register char ch;
  822.  
  823.     char keyword[32];
  824.     char buffer[82];
  825.  
  826.     while( *TokenPtr && (*TokenPtr==' ') )
  827.     TokenPtr++;
  828.  
  829.     if( *TokenPtr )
  830.     {   ptr = NULL;
  831.     do {
  832.         len = 0;
  833.         while( *TokenPtr && (*TokenPtr!=' ') )
  834.         if( len<31 )
  835.         {   ch = *TokenPtr++;
  836.             keyword[len++] = ToUpper(ch);
  837.         } else TokenPtr++;
  838.         keyword[len]='\0';
  839.  
  840.         if( ptr )
  841.         {   tmp = &ptr->info;
  842.         ptr = (void __far*)0;
  843.         } else tmp = &HelpInfo;
  844.  
  845.         while( *tmp )
  846.         {   res = _fstrcmp(keyword,(*tmp)->keyword);
  847.         if( res<0 )
  848.         {   if( PrefixString(keyword,(*tmp)->keyword) )
  849.             {   ptr = *tmp;
  850.             if( ptr->next && 
  851.                 PrefixString(keyword,ptr->next->keyword) )
  852.             {   if( CommandActive ) WriteChar('\n');
  853.                 WriteString("Ambiguous help topic requested!\n");
  854.                 CommandActive = False;
  855.                 return;
  856.             } else break;
  857.             } else break;
  858.         } else if( res==0 ) 
  859.         {   ptr = *tmp;
  860.             break;
  861.         }
  862.         tmp = &(*tmp)->next;
  863.         }
  864.  
  865.         while( *TokenPtr && (*TokenPtr==' ') )
  866.         TokenPtr++;
  867.     } while( *TokenPtr && ptr );
  868.  
  869.     if( !ptr || !ptr->fpos )
  870.     {   if( CommandActive )
  871.         WriteChar('\n');
  872.         WriteString("No available help on requested topic!\n");
  873.         CommandActive=False;
  874.         return;
  875.     } else pos=ptr->fpos;
  876.     } else pos=0;
  877.  
  878.  
  879.     if( !(fp=fopen(HelpFileName,"r")) )
  880.     RasMolFatalExit("Command Error: Unable to reopen help file!");
  881.  
  882.     if( CommandActive )
  883.     WriteChar('\n');
  884.     CommandActive = False;
  885.  
  886.     fseek(fp,pos,0);
  887.     while( fgets(buffer,80,fp) )
  888.     if( *buffer!='?' )
  889.     {   WriteString(buffer);
  890.     } else break;
  891.     fclose(fp);
  892. }
  893.  
  894.  
  895. static int LookUpKeyword()
  896. {
  897.     register int mid,res;
  898.     register int lo, hi;
  899.  
  900.     if( TokenLength>MAXKEYLEN )
  901.     return( IdentTok );
  902.  
  903.     lo = KeyLen[TokenLength-1];
  904.     hi = KeyLen[TokenLength]-1;
  905.  
  906.     while( hi>=lo )
  907.     {   mid = (hi+lo)>>1;
  908.     res = _fstrcmp(TokenIdent,Keyword[mid].ident);
  909.     if( !res ) return( Keyword[mid].token );
  910.  
  911.     if( res>0 )
  912.     {      lo = mid+1;
  913.     } else hi = mid-1;
  914.     }
  915.     return( IdentTok );
  916. }
  917.  
  918.  
  919. static int FetchToken()
  920. {
  921.     register char ch;
  922.  
  923.     CurToken = 0;
  924.     while( True )
  925.     {    ch = *TokenPtr++;
  926.      if( !ch || (ch=='#') ) 
  927.          return(0);
  928.      if( isspace(ch) )
  929.          continue;
  930.  
  931.      TokenStart = TokenPtr-1;
  932.      if( isalpha(ch) )
  933.      {   TokenLength = 1;
  934.          *TokenIdent = ToUpper(ch);
  935.          while( IsIdentChar(*TokenPtr) && (TokenLength<32) )
  936.          {   ch = *TokenPtr++;
  937.          TokenIdent[TokenLength++] = ToUpper(ch);
  938.          }
  939.          if( TokenLength==32 )
  940.          {   CommandError("Identifier too long");
  941.          return(0);
  942.          } else TokenIdent[TokenLength] = '\0';
  943.          return( CurToken = LookUpKeyword() );
  944.  
  945.      } else if( isdigit(ch) )
  946.      {   TokenValue = ch-'0';
  947.          while( isdigit(*TokenPtr) )
  948.          TokenValue = 10*TokenValue + (*TokenPtr++)-'0';
  949.          return( CurToken = NumberTok );
  950.  
  951.      } else if( (ch=='\'') || (ch=='\"') || (ch=='`') )
  952.      {   TokenLength = 0;
  953.          while( *TokenPtr && (TokenLength<128) && (*TokenPtr!=ch) )
  954.          TokenIdent[TokenLength++] = *TokenPtr++;
  955.  
  956.          if( ch != *TokenPtr )
  957.          {   if( *TokenPtr )
  958.          {   CommandError("String constant unterminated");
  959.          } else CommandError("String constant too long");
  960.          return( 0 );
  961.          } else TokenPtr++;
  962.  
  963.          TokenIdent[TokenLength]='\0';
  964.          return( CurToken = StringTok );
  965.      } else if( ispunct(ch) )
  966.          return( CurToken = ch );
  967.     }
  968. }
  969.  
  970.  
  971. static int NextIf( token, error )
  972.     int token, error;
  973. {
  974.     if( FetchToken()!=token )
  975.     {   CommandError(ErrorMsg[error]);
  976.     return( True );
  977.     } else return( False );
  978. }
  979.  
  980.  
  981. static void FetchFloat( value, scale )
  982.     Long value;  int scale;
  983. {
  984.     register int count;
  985.     register int mant;
  986.  
  987.     if( !value && !isdigit(*TokenPtr) )
  988.     {   CommandError("Invalid floating point number");
  989.     TokenValue = 0;
  990.     return;
  991.     }
  992.  
  993.     mant = 0;
  994.     count = 1;
  995.     while( isdigit(*TokenPtr) )
  996.     {   if( count < scale )
  997.     {   mant = 10*mant + (*TokenPtr-'0');
  998.         count *= 10;
  999.     }
  1000.     TokenPtr++;
  1001.     }
  1002.  
  1003.     mant = (scale*mant)/count;
  1004.     TokenValue = value*scale + mant;
  1005. }
  1006.  
  1007.  
  1008. static int ParseColour()
  1009. {
  1010.     switch( CurToken )
  1011.     {   case(BlueTok):        RVal=0;   GVal=0;   BVal=255; break;
  1012.     case(BlackTok):       RVal=0;   GVal=0;   BVal=0;   break;
  1013.     case(CyanTok):        RVal=0;   GVal=255; BVal=255; break;
  1014.     case(GreenTok):       RVal=0;   GVal=255; BVal=0;   break;
  1015.     case(GreenblueTok):   RVal=46;  GVal=139; BVal=87;  break;
  1016.     case(MagentaTok):     RVal=255; GVal=0;   BVal=255; break;
  1017.     case(OrangeTok):      RVal=255; GVal=165; BVal=0;   break;
  1018.     case(PurpleTok):      RVal=160; GVal=32;  BVal=240; break;
  1019.     case(RedTok):         RVal=255; GVal=0;   BVal=0;   break;
  1020.     case(RedorangeTok):   RVal=255; GVal=69;  BVal=0;   break;
  1021.     case(VioletTok):      RVal=238; GVal=130; BVal=238; break;
  1022.     case(WhiteTok):       RVal=255; GVal=255; BVal=255; break; 
  1023.     case(YellowTok):      RVal=255; GVal=255; BVal=0;   break;
  1024.  
  1025.     case('['):    RVal = GVal = BVal = 0;
  1026.  
  1027.               if( NextIf(NumberTok,ErrNotNum) ) { return(False);
  1028.               } else if( TokenValue>255 )
  1029.               {   CommandError(ErrorMsg[ErrBigNum]); return( False );
  1030.               } else RVal = (int)TokenValue;
  1031.  
  1032.               if( NextIf(',',ErrNotSep) ) return(False);
  1033.               if( NextIf(NumberTok,ErrNotNum) ) { return(False);
  1034.               } else if( TokenValue>255 )
  1035.               {   CommandError(ErrorMsg[ErrBigNum]); return( False );
  1036.               } else GVal = (int)TokenValue;
  1037.  
  1038.               if( NextIf(',',ErrNotSep) ) return(False);
  1039.               if( NextIf(NumberTok,ErrNotNum) ) { return(False);
  1040.               } else if( TokenValue>255 )
  1041.               {   CommandError(ErrorMsg[ErrBigNum]); return( False );
  1042.               } else BVal = (int)TokenValue;
  1043.  
  1044.               return( !NextIf(']',ErrNotBrac) );
  1045.  
  1046.     case(IdentTok): if( Interactive )
  1047.             return( LookUpColour(TokenIdent,&RVal,&GVal,&BVal) );
  1048.               
  1049.     default:  return(False);
  1050.     }
  1051.     return( True );
  1052. }
  1053.  
  1054.  
  1055. void DisplaySelectCount()
  1056. {
  1057.     char buffer[40];
  1058.  
  1059.     if( FileDepth == -1 )
  1060.     {   if( CommandActive )
  1061.        WriteChar('\n');
  1062.     CommandActive=False;
  1063.     
  1064.     if( SelectCount==0 )
  1065.     {   WriteString("No atoms selected!\n");
  1066.     } else if( SelectCount>1 )
  1067.     {   sprintf(buffer,"%ld atoms selected!\n",SelectCount);
  1068.         WriteString(buffer);
  1069.     } else WriteString("1 atom selected!\n");
  1070.     }
  1071.  
  1072.     if( DisplayMode )
  1073.     ReDrawFlag |= RFRefresh;
  1074.     AdviseUpdate(AdvSelectCount);
  1075. }
  1076.  
  1077.  
  1078. static void SelectZoneExpr( expr )
  1079.     Expr *expr;
  1080. {
  1081.     register Bond __far *bptr;
  1082.  
  1083.     if( !Database )
  1084.     return;
  1085.  
  1086.     SelectCount = 0;
  1087.     for( QChain=Database->clist; QChain; QChain=QChain->cnext )
  1088.     for( QGroup=QChain->glist; QGroup; QGroup=QGroup->gnext )
  1089.         for( QAtom=QGroup->alist; QAtom; QAtom=QAtom->anext )
  1090.         if( EvaluateExpr(expr) )
  1091.         {   QAtom->flag |= SelectFlag;
  1092.             SelectCount++;
  1093.         } else QAtom->flag &= ~SelectFlag;
  1094.     DisplaySelectCount();
  1095.  
  1096.     if( ZoneBoth )
  1097.     {   ForEachBond
  1098.        if( (bptr->srcatom->flag&bptr->dstatom->flag) & SelectFlag )
  1099.        {   bptr->flag |= SelectFlag;
  1100.        } else bptr->flag &= ~SelectFlag;
  1101.     } else
  1102.     ForEachBond
  1103.        if( (bptr->srcatom->flag|bptr->dstatom->flag) & SelectFlag )
  1104.        {   bptr->flag |= SelectFlag;
  1105.        } else bptr->flag &= ~SelectFlag;
  1106. }
  1107.  
  1108.  
  1109. static void RestrictZoneExpr( expr )
  1110.     Expr *expr;
  1111. {
  1112.     register Bond __far *bptr;
  1113.     register int flag;
  1114.  
  1115.     if( !Database )
  1116.     return;
  1117.  
  1118.     DrawAtoms = False;   MaxAtomRadius = 0;
  1119.     DrawBonds = False;   MaxBondRadius = 0;
  1120.  
  1121.     SelectCount = 0;
  1122.     for( QChain=Database->clist; QChain; QChain=QChain->cnext )
  1123.     for( QGroup=QChain->glist; QGroup; QGroup=QGroup->gnext )
  1124.         for( QAtom=QGroup->alist; QAtom; QAtom=QAtom->anext )
  1125.         if( EvaluateExpr(expr) )
  1126.         {   QAtom->flag |= SelectFlag;
  1127.             SelectCount++;
  1128.  
  1129.             if( QAtom->flag & SphereFlag )
  1130.             {   DrawAtoms = True;
  1131.             if( QAtom->irad>MaxAtomRadius )
  1132.                 MaxAtomRadius = QAtom->irad;
  1133.             }
  1134.         }  else QAtom->flag &= ~(SelectFlag|SphereFlag);
  1135.     DisplaySelectCount();
  1136.  
  1137.     ForEachBond
  1138.     {   /* Ignore ZoneBoth setting! */
  1139.     flag = bptr->dstatom->flag & bptr->srcatom->flag;
  1140.     if( flag & SelectFlag )
  1141.     {   bptr->flag |= SelectFlag;
  1142.         if( bptr->flag & CylinderFlag )
  1143.         {   DrawBonds = True;
  1144.         if( bptr->irad>MaxBondRadius )
  1145.             MaxBondRadius = bptr->irad;
  1146.         } else if( bptr->flag&WireFlag )
  1147.         DrawBonds = True;
  1148.     } else bptr->flag &= ~(SelectFlag|DrawBondFlag);
  1149.     }
  1150.  
  1151.     DetermineClipping();
  1152.     VoxelsClean = False;
  1153.     BucketFlag = False;
  1154. }
  1155.  
  1156.  
  1157. static void CentreZoneExpr( expr )
  1158.     Expr *expr;
  1159. {
  1160.     register Real x, y, z;
  1161.     register Long count;
  1162.  
  1163.     if( !Database )
  1164.     return;
  1165.  
  1166.     count = 0;
  1167.     x = y = z = 0.0;
  1168.     for( QChain=Database->clist; QChain; QChain=QChain->cnext )
  1169.     for( QGroup=QChain->glist; QGroup; QGroup=QGroup->gnext )
  1170.         for( QAtom=QGroup->alist; QAtom; QAtom=QAtom->anext )
  1171.         if( EvaluateExpr(expr) )
  1172.         {   x += (Real)QAtom->xorg;
  1173.             y += (Real)QAtom->yorg;
  1174.             z += (Real)QAtom->zorg;
  1175.             count++;
  1176.         }
  1177.  
  1178.     if( count )
  1179.     {   CenX = (Long)(x/count);
  1180.     CenY = (Long)(y/count);
  1181.     CenZ = (Long)(z/count);
  1182.     } else
  1183.     {   if( CommandActive ) WriteChar('\n');
  1184.     WriteString("No Atoms to Centre!\n");
  1185.     CommandActive = False;
  1186.     }
  1187. }
  1188.  
  1189.  
  1190. static Expr *ParseRange( neg )
  1191.     int neg;
  1192. {
  1193.     register Expr *tmp1,*tmp2;
  1194.     register char ch;
  1195.  
  1196.     tmp1 = AllocateNode();
  1197.     tmp1->type = OpLftProp|OpRgtVal;
  1198.     tmp1->rgt.val = neg? -(int)TokenValue : (int)TokenValue;
  1199.     tmp1->lft.val = PropResId;
  1200.  
  1201.     if( *TokenPtr == '-' )
  1202.     {   TokenPtr++;
  1203.     neg = (*TokenPtr=='-');
  1204.     if( neg ) TokenPtr++;
  1205.     FetchToken();
  1206.  
  1207.     if( CurToken != NumberTok )
  1208.     {   CommandError(ErrorMsg[ErrNotNum]);
  1209.         DeAllocateExpr( tmp1 );
  1210.         return( (Expr*)NULL );
  1211.     }
  1212.  
  1213.     tmp1->type |= OpMoreEq;
  1214.     tmp2 = AllocateNode();
  1215.     tmp2->rgt.ptr = tmp1;
  1216.     tmp2->type = OpAnd;
  1217.  
  1218.     tmp1 = AllocateNode();
  1219.     tmp1->type = OpLftProp|OpRgtVal|OpLessEq;
  1220.     tmp1->rgt.val = neg? -(int)TokenValue : (int)TokenValue;
  1221.     tmp1->lft.val = PropResId;
  1222.     tmp2->lft.ptr = tmp1;
  1223.     tmp1 = tmp2;
  1224.     } else tmp1->type |= OpEqual;
  1225.  
  1226.     if( *TokenPtr == ':' )
  1227.     TokenPtr++;
  1228.  
  1229.     ch = *TokenPtr;
  1230.     if( isalnum(ch) )
  1231.     {   ch = ToUpper(ch);
  1232.     TokenPtr++;
  1233.  
  1234.     tmp2 = AllocateNode();
  1235.     tmp2->type = OpAnd;
  1236.     tmp2->rgt.ptr = tmp1;
  1237.  
  1238.     tmp1 = AllocateNode();
  1239.     tmp1->type = OpEqual | OpLftProp | OpRgtVal;
  1240.     tmp1->lft.val = PropChain;               
  1241.     tmp1->rgt.val = ch;
  1242.  
  1243.     tmp2->lft.ptr = tmp1;
  1244.     tmp1 = tmp2;
  1245.     } else if( (ch=='?') || (ch=='%') || (ch=='*') )
  1246.     TokenPtr++;
  1247.  
  1248.     FetchToken();
  1249.     return( tmp1 );
  1250. }
  1251.  
  1252.  
  1253. static Expr *ParseExpression( level )
  1254.     int level;
  1255. {
  1256.     register Expr *tmp1,*tmp2;
  1257.     register int done, pred;
  1258.     register int neg;
  1259.  
  1260.     switch( level )
  1261.     {    case(0): /* Disjunctions */
  1262.           tmp1 = ParseExpression(1);
  1263.           while( (CurToken==OrTok) || (CurToken=='|') ||
  1264.              (CurToken==',') )
  1265.           {   if( CurToken=='|' )
  1266.               {   if( FetchToken()=='|' )
  1267.                   FetchToken();
  1268.               } else FetchToken();
  1269.  
  1270.               tmp2 = AllocateNode();
  1271.               tmp2->type = OpOr;
  1272.               tmp2->lft.ptr = tmp1;
  1273.               tmp2->rgt.ptr = NULL;
  1274.               if( !(tmp1=ParseExpression(1)) )
  1275.               {   DeAllocateExpr(tmp2);
  1276.               return( tmp1 );
  1277.               }
  1278.               tmp2->rgt.ptr = tmp1;
  1279.               tmp1 = tmp2;
  1280.           }
  1281.           return( tmp1 );
  1282.  
  1283.      case(1): /* Conjunctions */
  1284.           tmp1 = ParseExpression(2);
  1285.           while( (CurToken==AndTok) || (CurToken=='&') )
  1286.           {   if( CurToken=='&' )
  1287.               {   if( FetchToken()=='&' )
  1288.                   FetchToken();
  1289.               } else FetchToken();
  1290.  
  1291.               tmp2 = AllocateNode();
  1292.               tmp2->type = OpAnd;
  1293.               tmp2->lft.ptr = tmp1;
  1294.               tmp2->rgt.ptr = NULL;
  1295.               if( !(tmp1=ParseExpression(2)) )
  1296.               {   DeAllocateExpr(tmp2);
  1297.               return( tmp1 );
  1298.               }
  1299.               tmp2->rgt.ptr = tmp1;
  1300.               tmp1 = tmp2;
  1301.           }
  1302.           return( tmp1 );
  1303.  
  1304.      case(2): /* Primitives */
  1305.           if( IsPredTok(CurToken) || (CurToken==BackboneTok) )
  1306.           {   switch( CurToken )
  1307.               {   case(HelixTok):    if( InfoHelixCount<0 )
  1308.                          DetermineStructure();
  1309.                          pred = PredHelix;
  1310.                          break;
  1311.               case(SheetTok):    if( InfoLadderCount<0 )
  1312.                          DetermineStructure();
  1313.                          pred = PredSheet;
  1314.                          break;
  1315.               case(TurnTok):     if( InfoTurnCount<0 )
  1316.                          DetermineStructure();
  1317.                          pred = PredTurn;
  1318.                          break;
  1319.               case(CystineTok):  if( InfoSSBondCount<0 )
  1320.                          FindDisulphideBridges();
  1321.                          pred = PredCystine;     
  1322.                          break;
  1323.               case(BackboneTok): pred = PredMainChain;   break;
  1324.               case(SelectedTok): pred = PropSelect;      break;
  1325.               default:  pred = PredAbsChr(PredTokOrd(CurToken));
  1326.               }
  1327.  
  1328.               tmp1 = AllocateNode();
  1329.               tmp1->type = OpConst|OpLftProp|OpRgtVal;
  1330.               tmp1->lft.val = pred;
  1331.               FetchToken();
  1332.               return( tmp1 );
  1333.  
  1334.           } else if( IsPropTok(CurToken) )
  1335.           {   tmp1 = AllocateNode();
  1336.               tmp1->type = OpLftProp|OpRgtVal;
  1337.               switch( CurToken )
  1338.               {   case(TemperatureTok): pred = PropTemp;    break;
  1339.               case(RadiusTok):      pred = PropRad;     break;
  1340.               case(AtomNoTok):      pred = PropIdent;   break;
  1341.               case(ElemNoTok):      pred = PropElemNo;  break;
  1342.               case(ResNoTok):       pred = PropResId;   break;
  1343.               }
  1344.               tmp1->lft.val = pred;
  1345.  
  1346.               FetchToken();
  1347.               if( CurToken=='=' )
  1348.               {   tmp1->type |= OpEqual;
  1349.               if( FetchToken()=='=' )
  1350.                   FetchToken();
  1351.               } else if( CurToken=='<' )
  1352.               {   FetchToken();
  1353.               if( CurToken=='>' )
  1354.               {   tmp1->type |= OpNotEq;
  1355.                   FetchToken();
  1356.               } else if( CurToken=='=' )
  1357.               {   tmp1->type |= OpLessEq;
  1358.                   FetchToken();
  1359.               } else tmp1->type |= OpLess;
  1360.               } else if( CurToken=='>' )
  1361.               {   if( FetchToken()=='=' )
  1362.               {   tmp1->type |= OpMoreEq;
  1363.                   FetchToken();
  1364.               } else tmp1->type |= OpMore;
  1365.               } else if( (CurToken=='!') || (CurToken=='/') )
  1366.               {   if( NextIf('=',ErrBadExpr) )
  1367.               {   DeAllocateExpr( tmp1 );
  1368.                   return( (Expr*)NULL );
  1369.               } else tmp1->type |= OpNotEq;
  1370.               FetchToken();
  1371.               } else
  1372.               {   CommandError(ErrorMsg[ErrBadExpr]);
  1373.               DeAllocateExpr( tmp1 );
  1374.               return( (Expr*)NULL );
  1375.               }
  1376.  
  1377.  
  1378.               if( CurToken == '-' )
  1379.               {   FetchToken();
  1380.               neg = True;
  1381.               } else neg = False;
  1382.  
  1383.               if( CurToken!=NumberTok )
  1384.               {   CommandError(ErrorMsg[ErrNotNum]);
  1385.               DeAllocateExpr( tmp1 );
  1386.               return( (Expr*)NULL );
  1387.               } 
  1388.  
  1389.               if( neg )
  1390.               {     tmp1->rgt.val = -(int)TokenValue; 
  1391.               } else tmp1->rgt.val = (int)TokenValue;
  1392.               FetchToken();
  1393.               return( tmp1 );
  1394.               
  1395.           } else switch( CurToken )
  1396.           {   case('('):    FetchToken();
  1397.                     if( !(tmp1=ParseExpression(0)) )
  1398.                     return( (Expr*)NULL );
  1399.  
  1400.                     if( CurToken!=')' )
  1401.                     {   CommandError(ErrorMsg[ErrParen]);
  1402.                     DeAllocateExpr( tmp1 );
  1403.                     return( (Expr*)NULL );
  1404.                     }
  1405.                     FetchToken();
  1406.                     return(tmp1);
  1407.  
  1408.               case('!'): case('~'):
  1409.               case(NotTok): FetchToken();
  1410.                     if( !(tmp1=ParseExpression(2)) )
  1411.                     return( (Expr*)NULL );
  1412.  
  1413.                     tmp2 = AllocateNode();
  1414.                     tmp2->type = OpNot | OpRgtVal;
  1415.                     tmp2->lft.ptr = tmp1;
  1416.                     return( tmp2 );
  1417.  
  1418.               case('-'):    if( NextIf(NumberTok,ErrNotNum) )
  1419.                     return( (Expr*)NULL );
  1420.                     return( ParseRange(True) );
  1421.  
  1422.               case(NumberTok):
  1423.                     return( ParseRange(False) );
  1424.  
  1425.               case(WithinTok):
  1426.                     if( NextIf('(',ErrFunc) )
  1427.                     return( (Expr*)NULL );
  1428.  
  1429.                     FetchToken();
  1430.                     if( CurToken==NumberTok )
  1431.                     {   if( *TokenPtr=='.' )
  1432.                     {   TokenPtr++;
  1433.                         FetchFloat(TokenValue,250);
  1434.                     }
  1435.                     } else if( CurToken!='.' )
  1436.                     {   CommandError(ErrorMsg[ErrNotNum]);
  1437.                     return( (Expr*)NULL );
  1438.                     } else FetchFloat(0,250);
  1439.  
  1440.                     if( TokenValue>10000 )
  1441.                     {   CommandError(ErrorMsg[ErrBigNum]);
  1442.                     return( (Expr*)NULL );
  1443.                     } else pred = (int)TokenValue;
  1444.                     if( NextIf(',',ErrNotSep) )
  1445.                     return( (Expr*)NULL );
  1446.  
  1447.                     FetchToken();
  1448.                     if( !(tmp1=ParseExpression(0)) )
  1449.                     return( (Expr*)NULL );
  1450.  
  1451.                     if( CurToken!=')' )
  1452.                     {   CommandError(ErrorMsg[ErrParen]);
  1453.                     DeAllocateExpr( tmp1 );
  1454.                     return( (Expr*)NULL );
  1455.                     }
  1456.  
  1457.                     FetchToken();
  1458.                     if( !pred )
  1459.                     return( tmp1 );
  1460.  
  1461.                     tmp2 = AllocateNode();
  1462.                     tmp2->type = OpWithin;
  1463.                     tmp2->lft.limit = (Long)pred*pred;
  1464.                     tmp2->rgt.set = BuildAtomSet(tmp1);
  1465.                     DeAllocateExpr(tmp1);
  1466.                     return( tmp2 );
  1467.  
  1468.               default:      if( CurToken==IdentTok )
  1469.                     {   tmp1 = LookUpSetExpr(TokenIdent);
  1470.                     if( !tmp1 ) 
  1471.                         tmp1 = LookUpElement(TokenIdent);
  1472.  
  1473.                     if( tmp1 )
  1474.                     {   FetchToken();
  1475.                         return(tmp1);
  1476.                     }
  1477.                     }
  1478.  
  1479.                     TokenPtr = TokenStart;
  1480.                     done = ParsePrimitiveExpr(&TokenPtr);
  1481.                     FetchToken();
  1482.  
  1483.                     if( !done )
  1484.                     {   CommandError(ErrorMsg[ErrBadExpr]);
  1485.                     DeAllocateExpr( QueryExpr );
  1486.                     return( (Expr*)NULL );
  1487.                     } else return( QueryExpr );
  1488.           }
  1489.     }
  1490.     return( (Expr*)NULL );
  1491. }
  1492.  
  1493. static void ExecuteSetCommand()
  1494. {
  1495.     register int option;
  1496.  
  1497.     switch( FetchToken() )
  1498.     {   case(SlabTok):
  1499.         case(SlabModeTok):
  1500.         option = -1;
  1501.         FetchToken();
  1502.         if( CurToken==RejectTok )
  1503.         {   option = SlabReject;
  1504.         } else if( CurToken==HalfTok )
  1505.         {   option = SlabHalf;
  1506.         } else if( CurToken==HollowTok )
  1507.         {   option = SlabHollow;
  1508.         } else if( CurToken==SolidTok )
  1509.         {   option = SlabClose;
  1510.         } else if( CurToken==SectionTok )
  1511.         option = SlabSection;
  1512.  
  1513.         if( option != -1 )
  1514.         {   if( UseSlabPlane && (SlabMode!=option) )
  1515.             ReDrawFlag |= RFRefresh;
  1516.         SlabMode = option;
  1517.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1518.         break;
  1519.  
  1520.     case(ShadowTok):
  1521.         FetchToken();
  1522.         if( CurToken==TrueTok )
  1523.         {   UseShadow = True;
  1524.         ReviseInvMatrix();
  1525.         VoxelsClean = False;
  1526.         UseSlabPlane = False;
  1527.         ReDrawFlag |= RFRefresh;
  1528.         ReAllocBuffers();
  1529.         } else if( CurToken==FalseTok )
  1530.         {   ReDrawFlag |= RFRefresh;
  1531.         UseShadow = False;
  1532.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1533.         break;
  1534.                   
  1535.     case(SpecularTok):
  1536.         FetchToken();
  1537.         if( CurToken==TrueTok )
  1538.         {   FakeSpecular = True;
  1539.         ReDrawFlag |= RFColour;
  1540.         } else if( CurToken==FalseTok )
  1541.         {   FakeSpecular = False;
  1542.         ReDrawFlag |= RFColour;
  1543.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1544.         break;
  1545.  
  1546.     case(SpecPowerTok):
  1547.         FetchToken();
  1548.         if( !CurToken )
  1549.         {   SpecPower = 8;
  1550.         ReDrawFlag |= RFColour;
  1551.         } else if( CurToken==NumberTok )
  1552.         {   if( TokenValue<=100 )
  1553.         {   ReDrawFlag |= RFColour;
  1554.             SpecPower = (int)TokenValue;
  1555.         } else 
  1556.             CommandError(ErrorMsg[ErrBigNum]);
  1557.         } else CommandError(ErrorMsg[ErrNotNum]);
  1558.         break;
  1559.  
  1560.     case(AmbientTok):
  1561.         FetchToken();
  1562.         if( !CurToken )
  1563.         {   ReDrawFlag |= RFColour;
  1564.         Ambient = DefaultAmbient;
  1565.         } else if( CurToken==NumberTok )
  1566.         {   if( TokenValue<=100 )
  1567.         {   Ambient = TokenValue/100.0;
  1568.             ReDrawFlag |= RFColour;
  1569.         } else
  1570.             CommandError(ErrorMsg[ErrBigNum]); 
  1571.         } else CommandError(ErrorMsg[ErrNotNum]);
  1572.         break;
  1573.  
  1574.     case(HeteroTok):
  1575.         FetchToken();
  1576.         if( CurToken==TrueTok )
  1577.         {   HetaGroups = True;
  1578.         } else if( CurToken==FalseTok )
  1579.         {   HetaGroups = False;
  1580.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1581.         break;
  1582.                   
  1583.     case(HydrogenTok):
  1584.         FetchToken();
  1585.         if( CurToken==TrueTok )
  1586.         {   Hydrogens = True;
  1587.         } else if( CurToken==FalseTok )
  1588.         {   Hydrogens = False;
  1589.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1590.         break;
  1591.                   
  1592.  
  1593.     case(BackgroundTok):
  1594.         FetchToken();
  1595.         if( !CurToken )
  1596.         {   CommandError(ErrorMsg[ErrNoCol]);
  1597.         } else if( ParseColour() )
  1598.         {   ReDrawFlag |= RFColour;
  1599.         BackR = RVal;
  1600.         BackG = GVal;
  1601.         BackB = BVal;
  1602. #ifndef IBMPC
  1603.         FBClear = False;
  1604. #endif
  1605.         } else if( CurToken )
  1606.         CommandError(ErrorMsg[ErrColour]);
  1607.         break;
  1608.  
  1609.     case(BondModeTok):
  1610.         FetchToken();
  1611.         if( !CurToken || (CurToken==AndTok) )
  1612.         {   ZoneBoth = True;
  1613.         } else if( CurToken==OrTok )
  1614.         {   ZoneBoth = False;
  1615.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1616.         break;
  1617.         
  1618.     case(HBondTok):
  1619.         FetchToken();
  1620.         if( (CurToken==BackboneTok) || (CurToken==MainChainTok) )
  1621.         {   ReDrawFlag |= RFRefresh;
  1622.         HBondMode = True;
  1623.         } else if( !CurToken || (CurToken==SidechainTok) )
  1624.         {   ReDrawFlag |= RFRefresh;
  1625.         HBondMode = False;
  1626.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1627.         break;
  1628.  
  1629.     case(SSBondTok):
  1630.         FetchToken();
  1631.         if( (CurToken==BackboneTok) || (CurToken==MainChainTok) )
  1632.         {   ReDrawFlag |= RFRefresh;
  1633.         SSBondMode = True;
  1634.         } else if( !CurToken || (CurToken==SidechainTok) )
  1635.         {   ReDrawFlag |= RFRefresh;
  1636.         SSBondMode = False;
  1637.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1638.         break;
  1639.  
  1640.     case(HourGlassTok):
  1641.         FetchToken();
  1642.         if( CurToken==TrueTok )
  1643.         {   UseHourGlass = True;
  1644.         } else if( CurToken==FalseTok )
  1645.         {   UseHourGlass = False;
  1646.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1647.         break;
  1648.  
  1649.     case(StrandsTok):
  1650.         FetchToken();
  1651.         if( !CurToken )
  1652.         {   ReDrawFlag |= RFRefresh;
  1653.         SplineCount = 5;
  1654.         } else if( CurToken==NumberTok )
  1655.         {   if( (TokenValue>0) && (TokenValue<=5) )
  1656.         {   SplineCount = (int)TokenValue;
  1657.             ReDrawFlag |= RFRefresh;
  1658.         } else if( TokenValue==9 )
  1659.         {   ReDrawFlag |= RFRefresh;
  1660.             SplineCount = 9;
  1661.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1662.         } else CommandError(ErrorMsg[ErrNotNum]);
  1663.         break;
  1664.  
  1665.     case(MouseTok):
  1666.         FetchToken();
  1667.         if( !CurToken || (CurToken==RasMolTok) )
  1668.         {   if( Interactive )
  1669.             SetMouseMode( MMRasMol );
  1670.         } else if( CurToken==InsightTok )
  1671.         {   if( Interactive )
  1672.             SetMouseMode( MMInsight );
  1673.         } else if( CurToken==QuantaTok )
  1674.         {   if( Interactive )
  1675.             SetMouseMode( MMQuanta );
  1676.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1677.         break;
  1678.  
  1679.     case(DisplayTok):
  1680.         FetchToken();
  1681.         if( !CurToken || (CurToken==NormalTok) )
  1682.         {   ReDrawFlag |= RFRefresh | RFColour;
  1683.         DisplayMode = 0;
  1684.         } else if( CurToken==SelectedTok )
  1685.         {   ReDrawFlag |= RFRefresh | RFColour;
  1686.         DisplayMode = 1;
  1687.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1688.         break;
  1689.  
  1690.     case(AxesTok):
  1691.         FetchToken();
  1692.         if( !CurToken || (CurToken==FalseTok) )
  1693.         {   ReDrawFlag |= RFRefresh;
  1694.         DrawAxes = False;
  1695.         } else if( CurToken == TrueTok )
  1696.         {   ReDrawFlag |= RFRefresh;
  1697.         DrawAxes = True;
  1698.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1699.         break;
  1700.  
  1701.     case(BoundBoxTok):
  1702.         FetchToken();
  1703.         if( !CurToken || (CurToken==FalseTok) )
  1704.         {   ReDrawFlag |= RFRefresh;
  1705.         DrawBoundBox = False;
  1706.         } else if( CurToken == TrueTok )
  1707.         {   ReDrawFlag |= RFRefresh;
  1708.         DrawBoundBox = True;
  1709.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1710.         break;
  1711.  
  1712.     case(UnitCellTok):
  1713.         FetchToken();
  1714.         if( !CurToken || (CurToken==FalseTok) )
  1715.         {   ReDrawFlag |= RFRefresh;
  1716.         DrawUnitCell = False;
  1717.         } else if( CurToken == TrueTok )
  1718.         {   ReDrawFlag |= RFRefresh;
  1719.         DrawUnitCell = True;
  1720.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1721.         break;
  1722.  
  1723.     case(VectPSTok):
  1724.         FetchToken();
  1725.         if( !CurToken || (CurToken==FalseTok) )
  1726.         {   UseOutLine = False;
  1727.         } else if( CurToken == TrueTok )
  1728.         {   UseOutLine = True;
  1729.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1730.         break;
  1731.  
  1732.     case(KinemageTok):
  1733.         FetchToken();
  1734.         if( !CurToken || (CurToken==FalseTok) )
  1735.         {   KinemageFlag = False;
  1736.         } else if( CurToken == TrueTok )
  1737.         {   KinemageFlag = True;
  1738.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1739.         break;
  1740.  
  1741.     case(MenusTok):
  1742.         FetchToken();
  1743.         if( !CurToken || (CurToken==TrueTok) )
  1744.         {   EnableMenus(True);
  1745.         } else if( CurToken == FalseTok )
  1746.         {   EnableMenus(False);
  1747.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1748.         break;
  1749.  
  1750.     case(RadiusTok):
  1751.         FetchToken();
  1752.         if( !CurToken )
  1753.         {   ProbeRadius = SolventDots? 300 : 0;
  1754.         } else if( CurToken==NumberTok )
  1755.         {   if( *TokenPtr=='.' )
  1756.         {   TokenPtr++;
  1757.             FetchFloat(TokenValue,250);
  1758.         }
  1759.  
  1760.         if( TokenValue>500 )
  1761.         {   CommandError(ErrorMsg[ErrBigNum]);
  1762.         } else ProbeRadius = (int)TokenValue;
  1763.         } else if( CurToken=='.' )
  1764.         {   FetchFloat(0,250);
  1765.         if( TokenValue>500 )
  1766.         {   CommandError(ErrorMsg[ErrBigNum]);
  1767.         } else ProbeRadius = (int)TokenValue;
  1768.  
  1769.         } else CommandError(ErrorMsg[ErrNotNum]);
  1770.         break;
  1771.  
  1772.     case(SolventTok):
  1773.         FetchToken();
  1774.         if( !CurToken || (CurToken==FalseTok) )
  1775.         {   SolventDots = False;
  1776.         ProbeRadius = 0;
  1777.         } else if( CurToken == TrueTok )
  1778.         {   SolventDots = True;
  1779.         ProbeRadius = 300;
  1780.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1781.         break;
  1782.  
  1783.     case(FontSizeTok):
  1784.         FetchToken();
  1785.         if( CurToken==NumberTok )
  1786.         {   if( TokenValue<=32 )
  1787.         {   if( DrawLabels )
  1788.             ReDrawFlag |= RFRefresh;
  1789.             SetFontSize((int)TokenValue);
  1790.         } else CommandError(ErrorMsg[ErrBigNum]);
  1791.         } else if( !CurToken )
  1792.         {   if( DrawLabels )
  1793.             ReDrawFlag |= RFRefresh;
  1794.         SetFontSize(8);
  1795.         } else CommandError(ErrorMsg[ErrBadOpt]);
  1796.         break;
  1797.  
  1798.     default:
  1799.         CommandError(ErrorMsg[ErrParam]);
  1800.     }
  1801. }
  1802.  
  1803.  
  1804. static void ExecuteColourCommand()
  1805. {
  1806.     register int flag;
  1807.  
  1808.     flag = 0;
  1809.     switch( FetchToken() )
  1810.     {   case(AtomTok):
  1811.         FetchToken();
  1812.     default:
  1813.         if( !CurToken )
  1814.         {   CommandError(ErrorMsg[ErrNoCol]);
  1815.         } else switch( CurToken )
  1816.         {   case(CPKTok):         CPKColourAttrib(); 
  1817.                       ReDrawFlag |= RFColour; break;
  1818.  
  1819.         case(AminoTok):       AminoColourAttrib();
  1820.                       ReDrawFlag |= RFColour; break;
  1821.  
  1822.         case(ShapelyTok):     ShapelyColourAttrib();
  1823.                       ReDrawFlag |= RFColour; break;
  1824.         
  1825.         case(UserTok):        UserMaskAttrib(MaskColourFlag);
  1826.                       ReDrawFlag |= RFColour; break;
  1827.  
  1828.         case(GroupTok):       ScaleColourAttrib(GroupAttr);
  1829.                       ReDrawFlag |= RFColour; break;
  1830.  
  1831.         case(ChainTok):       ScaleColourAttrib(ChainAttr);
  1832.                       ReDrawFlag |= RFColour; break;
  1833.  
  1834.         case(ChargeTok):      ScaleColourAttrib(ChargeAttr);
  1835.                       ReDrawFlag |= RFColour; break;
  1836.  
  1837.         case(TemperatureTok): ScaleColourAttrib(TempAttr);
  1838.                       ReDrawFlag |= RFColour; break;
  1839.  
  1840.         case(StructureTok):   StructColourAttrib();
  1841.                       ReDrawFlag |= RFColour; break;
  1842.  
  1843.         default:  if( ParseColour() )
  1844.               {   MonoColourAttrib(RVal,GVal,BVal);
  1845.                   ReDrawFlag |= RFColour;
  1846.               } else CommandError(ErrorMsg[ErrColour]);
  1847.         }
  1848.         break;
  1849.  
  1850.     case(BondTok):    
  1851.         FetchToken();
  1852.         if( !CurToken )
  1853.         {   CommandError(ErrorMsg[ErrNoCol]);
  1854.         } else if( CurToken==NoneTok )
  1855.         {   ColourBondNone();
  1856.         ReDrawFlag |= RFColour;
  1857.         } else if( ParseColour() )
  1858.         {   ColourBondAttrib(RVal,GVal,BVal);
  1859.         ReDrawFlag |= RFColour;
  1860.         } else CommandError(ErrorMsg[ErrColour]);
  1861.         break;
  1862.  
  1863.     case(TraceTok):
  1864.     case(BackboneTok):
  1865.         FetchToken();
  1866.         if( !CurToken )
  1867.         {   CommandError(ErrorMsg[ErrNoCol]);
  1868.         } else if( CurToken==NoneTok )
  1869.         {   ColourBackNone();
  1870.         ReDrawFlag |= RFColour;
  1871.         } else if( ParseColour() )
  1872.         {   ColourBackAttrib(RVal,GVal,BVal);
  1873.         ReDrawFlag |= RFColour;
  1874.         } else CommandError(ErrorMsg[ErrColour]);
  1875.         break;
  1876.  
  1877.     case(SSBondTok):
  1878.         FetchToken();
  1879.         if( !CurToken )
  1880.         {   CommandError(ErrorMsg[ErrNoCol]);
  1881.         } else if( CurToken==NoneTok )
  1882.         {   ReDrawFlag |= RFColour;
  1883.         ColourHBondNone( False );
  1884.         } else if( ParseColour() )
  1885.         {   ReDrawFlag |= RFColour;
  1886.         ColourHBondAttrib(False,RVal,GVal,BVal);
  1887.         } else CommandError(ErrorMsg[ErrColour]);
  1888.         break;
  1889.  
  1890.     case(HBondTok):
  1891.         FetchToken();
  1892.         if( !CurToken )
  1893.         {   CommandError(ErrorMsg[ErrNoCol]);
  1894.         } else if( CurToken==NoneTok )
  1895.         {   ReDrawFlag |= RFColour;
  1896.         ColourHBondNone( True );
  1897.         } else if( CurToken==TypeTok )
  1898.         {   ReDrawFlag |= RFColour;
  1899.         ColourHBondType();
  1900.         } else if( ParseColour() )
  1901.         {   ReDrawFlag |= RFColour;
  1902.         ColourHBondAttrib(True,RVal,GVal,BVal);
  1903.         } else CommandError(ErrorMsg[ErrColour]);
  1904.         break;
  1905.  
  1906.     case(DotsTok):
  1907.         FetchToken();
  1908.         if( !CurToken )
  1909.         {   CommandError(ErrorMsg[ErrNoCol]);
  1910.         } else if( CurToken==PotentialTok )
  1911.         {   ReDrawFlag |= RFColour;
  1912.         ColourDotsPotential();
  1913.         } else if( ParseColour() )
  1914.         {   ReDrawFlag |= RFColour;
  1915.         ColourDotsAttrib(RVal,GVal,BVal);
  1916.         } else CommandError(ErrorMsg[ErrColour]);
  1917.         break;
  1918.  
  1919.     case(AxesTok):
  1920.     case(BoundBoxTok):
  1921.     case(UnitCellTok):
  1922.         FetchToken();
  1923.         if( !CurToken )
  1924.         {   CommandError(ErrorMsg[ErrNoCol]);
  1925.         } else if( ParseColour() )
  1926.         {   BoxR = RVal;  BoxG = GVal;  BoxB = BVal;
  1927.         ReDrawFlag |= RFColour;
  1928.         } else CommandError(ErrorMsg[ErrColour]);
  1929.         break;
  1930.  
  1931.     case(LabelTok):
  1932.         FetchToken();
  1933.         if( !CurToken )
  1934.         {   CommandError(ErrorMsg[ErrNoCol]);
  1935.         } else if( CurToken==NoneTok )
  1936.         {   ReDrawFlag |= RFColour;
  1937.         UseLabelCol = False;
  1938.         } else if( ParseColour() )
  1939.         {   LabR = RVal;  LabG = GVal;  LabB = BVal;
  1940.         ReDrawFlag |= RFColour;
  1941.         UseLabelCol = True;
  1942.         } else CommandError(ErrorMsg[ErrColour]);
  1943.         break;
  1944.  
  1945.     case(RibbonTok):   flag = RibColBoth;     break;
  1946.     case(Ribbon1Tok):  flag = RibColInside;   break;
  1947.     case(Ribbon2Tok):  flag = RibColOutside;  break;
  1948.     }
  1949.  
  1950.     if( flag )
  1951.     {   FetchToken();
  1952.     if( !CurToken )
  1953.     {   CommandError(ErrorMsg[ErrNoCol]);
  1954.     } else if( CurToken==NoneTok )
  1955.     {   ReDrawFlag |= RFColour;
  1956.         ColourRibbonNone(flag);
  1957.     } else if( ParseColour() )
  1958.     {   ReDrawFlag |= RFColour;
  1959.         ColourRibbonAttrib(flag,RVal,GVal,BVal);
  1960.     } else CommandError(ErrorMsg[ErrColour]);
  1961.     }
  1962. }
  1963.  
  1964.  
  1965. static void ExecuteShowCommand()
  1966. {
  1967.     register Chain __far *chn;
  1968.     register Group __far *grp;
  1969.     register int chain,count;
  1970.     register Real temp;
  1971.     register char *str;
  1972.     char buffer[40];
  1973.  
  1974.     switch( FetchToken() )
  1975.     {   case(InfoTok):
  1976.         DescribeMolecule();
  1977.         break;
  1978.  
  1979.     case(SequenceTok):
  1980.         if( CommandActive )
  1981.             WriteChar('\n');
  1982.         CommandActive = False;
  1983.         if( !Database )
  1984.             return;
  1985.  
  1986.         for( chn=Database->clist; chn; chn=chn->cnext )
  1987.         {   chain = (InfoChainCount<2);  count = 0;
  1988.             for( grp=chn->glist; grp; grp=grp->gnext )
  1989.             if( grp->alist && !(grp->alist->flag&HeteroFlag) )
  1990.             {   if( !chain )
  1991.                 {   WriteString("Chain ");
  1992.                 WriteChar(chn->ident);
  1993.                 WriteString(":\n");
  1994.                 chain = True;
  1995.                 }
  1996.  
  1997.                 if( count == 10 )
  1998.                 {   WriteChar('\n');
  1999.                 count = 1;
  2000.                 } else count++;
  2001.  
  2002.                 str = Residue[grp->refno];
  2003.                 WriteChar(str[0]);
  2004.                 WriteChar(str[1]);
  2005.                 WriteChar(str[2]);
  2006.  
  2007.                 sprintf(buffer,"%-3d ",grp->serno);
  2008.                 WriteString(buffer);
  2009.             }
  2010.             WriteChar('\n');
  2011.         }
  2012.  
  2013.         WriteChar('\n');
  2014.         break;
  2015.  
  2016.     case(SymmetryTok):
  2017.         if( CommandActive )
  2018.             WriteChar('\n');
  2019.         CommandActive = False;
  2020.  
  2021.         if( *InfoSpaceGroup )
  2022.         {   sprintf(buffer,"Space Group ...... %s\n",InfoSpaceGroup);
  2023.             WriteString(buffer);
  2024.  
  2025.             sprintf(buffer,"Unit cell A ...... %g\n",InfoCellA);
  2026.             WriteString(buffer);
  2027.             sprintf(buffer,"Unit cell B ...... %g\n",InfoCellB);
  2028.             WriteString(buffer);
  2029.             sprintf(buffer,"Unit cell C ...... %g\n",InfoCellC);
  2030.             WriteString(buffer);
  2031.  
  2032.             temp = Rad2Deg*InfoCellAlpha;
  2033.             sprintf(buffer,"Unit cell alpha .. %g\n",temp);
  2034.             WriteString(buffer);
  2035.             temp = Rad2Deg*InfoCellBeta;
  2036.             sprintf(buffer,"Unit cell beta ... %g\n",temp);
  2037.             WriteString(buffer);
  2038.             temp = Rad2Deg*InfoCellGamma;
  2039.             sprintf(buffer,"Unit cell gamma .. %g\n",temp);
  2040.             WriteString(buffer);
  2041.  
  2042.         } else WriteString("No crystal symmetry data!\n");
  2043.         WriteChar('\n');
  2044.         break;
  2045.  
  2046.     default:
  2047.         CommandError(ErrorMsg[ErrBadArg]);
  2048.     }
  2049. }
  2050.  
  2051. void ZapDatabase()
  2052. {
  2053.     register int i;
  2054.  
  2055.     for( i=0; i<8; i++ )
  2056.     DialValue[i] = 0.0;
  2057.     SelectCount = 0;
  2058.  
  2059.     DestroyDatabase();
  2060.     ResetSymbolTable();
  2061.     ResetTransform();
  2062.     ResetRenderer();
  2063.  
  2064.     ZoneBoth = True;
  2065.     HetaGroups = True;    
  2066.     Hydrogens = True;
  2067.  
  2068.     ResetColourMap();
  2069.     DefineColourMap();
  2070.     ClearBuffers();
  2071.     ReDrawFlag = 0;
  2072.  
  2073.     if( Interactive )
  2074.     {   UpdateScrollBars();
  2075.     ClearImage();
  2076.     }
  2077.     AdviseUpdate(AdvName);
  2078.     AdviseUpdate(AdvClass);
  2079.     AdviseUpdate(AdvIdent);
  2080. }
  2081.  
  2082.  
  2083. static void WriteImageFile( name, type )
  2084.     char *name;  int type;
  2085. {
  2086.     if( !type )
  2087. #ifdef EIGHTBIT
  2088.     type = GIFTok;
  2089. #else
  2090.     type = PPMTok;
  2091. #endif
  2092.  
  2093.  
  2094.     switch( type )
  2095.     {   case(GIFTok):     WriteGIFFile(name);             break;
  2096.     case(BMPTok):     WriteBMPFile(name);             break;
  2097.     case(PPMTok):     WritePPMFile(name,True);        break;
  2098.     case(SUNTok):     WriteRastFile(name,False);      break;
  2099.     case(SUNRLETok):  WriteRastFile(name,True);       break;
  2100.     case(PICTTok):    WritePICTFile(name);            break;
  2101.     case(IRISTok):    WriteIRISFile(name);            break;
  2102.     case(EPSFTok):    WriteEPSFFile(name,True,True);  break;
  2103.     case(MonoPSTok):  WriteEPSFFile(name,False,True); break;
  2104.     case(VectPSTok):  WriteVectPSFile(name);          break;
  2105.  
  2106.     case(RasMolTok):
  2107.     case(ScriptTok):     WriteScriptFile(name);     break;
  2108.     case(POVRayTok):     WritePOVRayFile(name);     break;
  2109.     case(KinemageTok):   WriteKinemageFile(name);   break;
  2110.     case(MolScriptTok):  WriteMolScriptFile(name);  break;
  2111.     }
  2112. }
  2113.  
  2114.  
  2115. static void ExecuteConnect( flag )
  2116.     int flag;
  2117. {
  2118.     register Bond __far *bptr;
  2119.  
  2120.     if( Database )
  2121.     {   ForEachBond
  2122.         if( bptr->col )
  2123.         Shade[Colour2Shade(bptr->col)].refcount--;
  2124.     ReDrawFlag |= RFRefresh|RFColour;
  2125.     CreateMoleculeBonds(True,flag);
  2126.         EnableWireFrame(True,0);
  2127.     }
  2128. }
  2129.  
  2130. #ifdef IBMPC
  2131. /* Avoid Optimizer Warning */
  2132. #pragma optimize("g",off)
  2133. #endif
  2134.  
  2135. int ExecuteCommand()
  2136. {
  2137.     register char *param;
  2138.     register int option;
  2139.     register int i,done;
  2140.     register Long temp;
  2141.     FILE *script;
  2142.  
  2143.     TokenPtr = CurLine;
  2144.     if( !FetchToken() )
  2145.     {   TokenPtr = NULL;
  2146.     return( False );
  2147.     }
  2148.  
  2149.     switch( CurToken )
  2150.     {   case(LoadTok):    if( !Database )
  2151.               {   FetchToken();
  2152.                   option = FormatPDB;
  2153.                   if( !*TokenPtr || *TokenPtr==' ' )
  2154.                   {   if( CurToken==PDBTok )
  2155.                   {   FetchToken();  option = FormatPDB;
  2156.                   } else if( CurToken==MDLTok )
  2157.                   {   FetchToken();  option = FormatMDL;
  2158.                   } else if( CurToken==XYZTok )
  2159.                   {   FetchToken();  option = FormatXYZ;
  2160.                   } else if( CurToken==AlchemyTok )
  2161.                   {   FetchToken();  option = FormatAlchemy;
  2162.                   } else if( CurToken==CharmmTok )
  2163.                   {   FetchToken();  option = FormatCharmm;
  2164.                   } else if( CurToken==Mol2Tok )
  2165.                   {   FetchToken();  option = FormatMol2;
  2166.                   }
  2167.                   }
  2168.  
  2169.                   done = (FileDepth == -1);
  2170.                   if( !CurToken )
  2171.                   {   CommandError(ErrorMsg[ErrFilNam]);
  2172.                   break;
  2173.                   } else if( CurToken==StringTok )
  2174.                   {      FetchFile(option,done,TokenIdent);
  2175.                   } else FetchFile(option,done,TokenStart);
  2176.                   CurToken = 0;
  2177.  
  2178.                   if( Database )
  2179.                   {   ReDrawFlag |= RFRefresh | RFColour;
  2180.                   if( InfoBondCount < 1 )
  2181.                   {   EnableBackBone(False,80);
  2182.                   } else EnableWireFrame(True,0);
  2183.                   CPKColourAttrib();
  2184.                   }
  2185.               } else CommandError(ErrorMsg[ErrBadLoad]);
  2186.               break;
  2187.  
  2188.     case(SelectTok):  FetchToken();
  2189.               if( !CurToken )
  2190.               {   option = NormAtomFlag;
  2191.                   if( HetaGroups ) option |= HeteroFlag;
  2192.                   if( Hydrogens )  option |= HydrogenFlag;
  2193.                   SelectZone(option);
  2194.               } else if( CurToken==AllTok )
  2195.               {   SelectZone(AllAtomFlag);
  2196.               } else if( CurToken==NoneTok )
  2197.               {   SelectZone(0x00);
  2198.               } else
  2199.                   if( QueryExpr=ParseExpression(0) )
  2200.                   {   if( !CurToken )
  2201.                   {   SelectZoneExpr(QueryExpr);
  2202.                   } else CommandError(ErrorMsg[ErrSyntax]);
  2203.                   DeAllocateExpr(QueryExpr);
  2204.                   }
  2205.               break;
  2206.  
  2207.     case(RestrictTok):
  2208.               FetchToken();
  2209.               if( !CurToken )
  2210.               {   option = NormAtomFlag;
  2211.                   if( HetaGroups ) option |= HeteroFlag;
  2212.                   if( Hydrogens )  option |= HydrogenFlag;
  2213.                   RestrictZone(option);
  2214.                   ReDrawFlag |= RFRefresh;
  2215.               } else if( CurToken==AllTok )
  2216.               {   RestrictZone(AllAtomFlag);
  2217.                   ReDrawFlag |= RFRefresh;
  2218.               } else if( CurToken==NoneTok )
  2219.               {   RestrictZone(0x00);
  2220.                   ReDrawFlag |= RFRefresh;
  2221.               } else
  2222.                   if( QueryExpr=ParseExpression(0) )
  2223.                   {   if( !CurToken )
  2224.                   {   RestrictZoneExpr(QueryExpr);
  2225.                       ReDrawFlag |= RFRefresh;
  2226.                   } else CommandError(ErrorMsg[ErrSyntax]);
  2227.                   DeAllocateExpr(QueryExpr);
  2228.                   } 
  2229.               break;
  2230.  
  2231.  
  2232.     case(ColourTok):  ExecuteColourCommand();
  2233.               break;
  2234.  
  2235.  
  2236.     case(WireframeTok):
  2237.               FetchToken();
  2238.               if( CurToken==FalseTok )
  2239.               {   ReDrawFlag |= RFRefresh;
  2240.                   DisableWireFrame();
  2241.               } else if( (CurToken==TrueTok) || !CurToken )
  2242.               {   ReDrawFlag |= RFRefresh;
  2243.                   EnableWireFrame(True,0);
  2244.               } else if( CurToken==NumberTok )
  2245.               {   if( *TokenPtr=='.' )
  2246.                   {   TokenPtr++;
  2247.                   FetchFloat(TokenValue,250);
  2248.                   }
  2249.  
  2250.                   if( TokenValue<500 )
  2251.                   {   EnableWireFrame(False,(int)TokenValue);
  2252.                   ReDrawFlag |= RFRefresh;
  2253.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2254.               } else if( CurToken=='.' )
  2255.               {   FetchFloat(0,250);
  2256.                   if( TokenValue<500 )
  2257.                   {   EnableWireFrame(False,(int)TokenValue);
  2258.                   ReDrawFlag |= RFRefresh;
  2259.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2260.               } else CommandError(ErrorMsg[ErrBadArg]);
  2261.               break;
  2262.  
  2263.     case(TraceTok):
  2264.     case(BackboneTok):
  2265.               FetchToken();
  2266.               if( CurToken==FalseTok )
  2267.               {   ReDrawFlag |= RFRefresh;
  2268.                   DisableBackBone();
  2269.               } else if( (CurToken==TrueTok) || !CurToken )
  2270.               {   ReDrawFlag |= RFRefresh;
  2271.                   EnableBackBone(True,0);
  2272.               } else if( CurToken==NumberTok )
  2273.               {   if( *TokenPtr=='.' )
  2274.                   {   TokenPtr++;
  2275.                   FetchFloat(TokenValue,250);
  2276.                   }
  2277.  
  2278.  
  2279.                   if( TokenValue<500 )
  2280.                   {   EnableBackBone(False,(int)TokenValue);
  2281.                   ReDrawFlag |= RFRefresh;
  2282.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2283.               } else if( CurToken=='.' )
  2284.               {   FetchFloat(0,250);
  2285.                   if( TokenValue<500 )
  2286.                   {   EnableBackBone(False,(int)TokenValue);
  2287.                   ReDrawFlag |= RFRefresh;
  2288.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2289.               } else CommandError(ErrorMsg[ErrBadArg]);
  2290.               break;
  2291.  
  2292.     case(CPKTok):
  2293.     case(SpacefillTok):
  2294.               FetchToken();
  2295.               if( CurToken==FalseTok )
  2296.               {   ReDrawFlag |= RFRefresh;
  2297.                   DisableSpacefill();
  2298.               } else if( CurToken==NumberTok )
  2299.               {   if( *TokenPtr=='.' )
  2300.                   {   TokenPtr++;
  2301.                   FetchFloat(TokenValue,250);
  2302.                   }
  2303.  
  2304.                   if( TokenValue<=500 )
  2305.                   {   SetRadiusValue(MaxFun((int)TokenValue,1));
  2306.                   ReDrawFlag |= RFRefresh;
  2307.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2308.               } else if( CurToken=='.' )
  2309.               {   FetchFloat(0,250);
  2310.                   if( TokenValue<=500 )
  2311.                   {   SetRadiusValue(MaxFun((int)TokenValue,1));
  2312.                   ReDrawFlag |= RFRefresh;
  2313.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2314.               } else if( CurToken==UserTok )
  2315.               {   UserMaskAttrib(MaskRadiusFlag);
  2316.                   ReDrawFlag |= RFRefresh;
  2317.               } else if( CurToken==TemperatureTok )
  2318.               {   ReDrawFlag |= RFRefresh;
  2319.                   SetRadiusTemperature();
  2320.               } else if( (CurToken==TrueTok) || !CurToken )
  2321.               {   ReDrawFlag |= RFRefresh;
  2322.                   SetVanWaalRadius();
  2323.               } else CommandError(ErrorMsg[ErrBadArg]);
  2324.               break;
  2325.  
  2326.     case(SSBondTok):  FetchToken();
  2327.               if( CurToken==NumberTok )
  2328.               {   if( *TokenPtr=='.' )
  2329.                   {   TokenPtr++;
  2330.                   FetchFloat(TokenValue,250);
  2331.                   }
  2332.  
  2333.                   if( TokenValue<=500 )
  2334.                   {   SetHBondStatus(False,True,(int)TokenValue);
  2335.                   ReDrawFlag |= RFRefresh;
  2336.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2337.               } else if( CurToken=='.' )
  2338.               {   FetchFloat(0,250);
  2339.                   if( TokenValue<=500 )
  2340.                   {   SetHBondStatus(False,True,(int)TokenValue);
  2341.                   ReDrawFlag |= RFRefresh;
  2342.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2343.               } else if( CurToken==FalseTok )
  2344.               {   ReDrawFlag |= RFRefresh;
  2345.                   SetHBondStatus(False,False,0);
  2346.               } else if( (CurToken==TrueTok) || !CurToken )
  2347.               {   ReDrawFlag |= RFRefresh;
  2348.                   SetHBondStatus(False,True,0);
  2349.               } else CommandError(ErrorMsg[ErrBadArg]);
  2350.               break;
  2351.  
  2352.     case(HBondTok):   FetchToken();
  2353.               if( CurToken==NumberTok )
  2354.               {   if( *TokenPtr=='.' )
  2355.                   {   TokenPtr++;
  2356.                   FetchFloat(TokenValue,250);
  2357.                   }
  2358.  
  2359.                   if( TokenValue<=500 )
  2360.                   {   SetHBondStatus(True,True,(int)TokenValue);
  2361.                   ReDrawFlag |= RFRefresh;
  2362.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2363.               } else if( CurToken=='.' )
  2364.               {   FetchFloat(0,250);
  2365.                   if( TokenValue<=500 )
  2366.                   {   SetHBondStatus(True,True,(int)TokenValue);
  2367.                   ReDrawFlag |= RFRefresh;
  2368.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2369.               } else if( CurToken==FalseTok )
  2370.               {   ReDrawFlag |= RFRefresh;
  2371.                   SetHBondStatus(True,False,0);
  2372.               } else if( (CurToken==TrueTok) || !CurToken )
  2373.               {   ReDrawFlag |= RFRefresh;
  2374.                   SetHBondStatus(True,True,0);
  2375.               } else CommandError(ErrorMsg[ErrBadArg]);
  2376.               break;
  2377.  
  2378.     case(RibbonTok):  FetchToken();
  2379.               if( CurToken==NumberTok )
  2380.               {   if( *TokenPtr=='.' )
  2381.                   {   TokenPtr++;
  2382.                   FetchFloat(TokenValue,250);
  2383.                   }
  2384.  
  2385.                   if( TokenValue<=1000 )
  2386.                   {   SetRibbonStatus(True,RibbonFlag,
  2387.                           (int)TokenValue);
  2388.                   ReDrawFlag |= RFRefresh;
  2389.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2390.               } else if( CurToken=='.' )
  2391.               {   FetchFloat(0,250);
  2392.                   if( TokenValue<=1000 )
  2393.                   {   SetRibbonStatus(True,RibbonFlag,
  2394.                           (int)TokenValue);
  2395.                   ReDrawFlag |= RFRefresh;
  2396.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2397.               } else if( CurToken==FalseTok )
  2398.               {   ReDrawFlag |= RFRefresh;
  2399.                   SetRibbonStatus(False,RibbonFlag,0);
  2400.               } else if( (CurToken==TrueTok) || !CurToken )
  2401.               {   ReDrawFlag |= RFRefresh;
  2402.                   SetRibbonStatus(True,RibbonFlag,0);
  2403.               } else CommandError(ErrorMsg[ErrBadArg]);
  2404.               break;
  2405.  
  2406.     case(StrandsTok): FetchToken();
  2407.               if( CurToken==NumberTok )
  2408.               {   if( *TokenPtr=='.' )
  2409.                   {   TokenPtr++;
  2410.                   FetchFloat(TokenValue,250);
  2411.                   }
  2412.  
  2413.                   if( TokenValue<=1000 )
  2414.                   {   SetRibbonStatus(True,StrandFlag,
  2415.                           (int)TokenValue);
  2416.                   ReDrawFlag |= RFRefresh;
  2417.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2418.               } else if( CurToken=='.' )
  2419.               {   FetchFloat(0,250);
  2420.                   if( TokenValue<=1000 )
  2421.                   {   SetRibbonStatus(True,StrandFlag,
  2422.                           (int)TokenValue);
  2423.                   ReDrawFlag |= RFRefresh;
  2424.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2425.               } else if( CurToken==FalseTok )
  2426.               {   ReDrawFlag |= RFRefresh;
  2427.                   SetRibbonStatus(False,StrandFlag,0);
  2428.               } else if( (CurToken==TrueTok) || !CurToken )
  2429.               {   ReDrawFlag |= RFRefresh;
  2430.                   SetRibbonStatus(True,StrandFlag,0);
  2431.               } else CommandError(ErrorMsg[ErrBadArg]);
  2432.               break;
  2433.  
  2434.     case(DotsTok):    FetchToken();
  2435.               if( CurToken==NumberTok )
  2436.               {   if( TokenValue<=1000 )
  2437.                   {   if( TokenValue )
  2438.                   {   CalculateSurface((int)TokenValue);
  2439.                   } else CalculateSurface(1);
  2440.                   ReDrawFlag |= RFRefresh;
  2441.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2442.               } else if( CurToken==FalseTok )
  2443.               {   ReDrawFlag |= RFRefresh;
  2444.                   DeleteSurface();
  2445.               } else if( (CurToken==TrueTok) || !CurToken )
  2446.               {   ReDrawFlag |= RFRefresh;
  2447.                   CalculateSurface(100);
  2448.               } else CommandError(ErrorMsg[ErrBadArg]);
  2449.               break;
  2450.  
  2451.     case(SlabTok):    FetchToken();
  2452.               if( (CurToken==NumberTok) || (CurToken=='.') )
  2453.               {   if( CurToken==NumberTok )
  2454.                   {   if( *TokenPtr=='.' )
  2455.                   {   TokenPtr++;
  2456.                       FetchFloat(TokenValue,100);
  2457.                   } else TokenValue *= 100;
  2458.                   } else FetchFloat(0,100);
  2459.  
  2460.                   if( TokenValue<=10000 )
  2461.                   {   DialValue[7] = (TokenValue-5000)/5000.0;
  2462.                   /* UpdateScrollBars(); */
  2463.                   ReDrawFlag |= RFSlab;
  2464.                   UseSlabPlane = True;
  2465.                   UseShadow = False;
  2466.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2467.  
  2468.               } else if( CurToken==FalseTok )
  2469.               {   if( UseSlabPlane )
  2470.                   {   ReDrawFlag |= RFRefresh;
  2471.                   UseSlabPlane = False;
  2472.                   }
  2473.               } else if( !CurToken || (CurToken==TrueTok) )
  2474.               {   if( !UseSlabPlane )
  2475.                   {   ReDrawFlag |= RFRefresh;
  2476.                   UseSlabPlane = True;
  2477.                   UseShadow = False;
  2478.                   }
  2479.               } else CommandError(ErrorMsg[ErrSyntax]);
  2480.               break;
  2481.  
  2482.     case(ZoomTok):    FetchToken();
  2483.               if( (CurToken==NumberTok) || (CurToken=='.') )
  2484.               {   if( CurToken==NumberTok )
  2485.                   {   if( *TokenPtr=='.' )
  2486.                   {   TokenPtr++;
  2487.                       FetchFloat(TokenValue,100);
  2488.                   } else TokenValue *= 100;
  2489.                   } else FetchFloat(0,100);
  2490.  
  2491.                   if( TokenValue<=10000 )
  2492.                   {   DialValue[3] = (TokenValue-10000)/10000.0;
  2493.                   ReDrawFlag |= RFZoom;
  2494.                   } else if( Database )
  2495.                   {   /* Magnification */
  2496.                   TokenValue -= 10000;
  2497.                   temp = (Long)(MaxZoom*10000);
  2498.                   if( TokenValue<=temp )
  2499.                   {   DialValue[3] = (Real)TokenValue/temp;
  2500.                       ReDrawFlag |= RFZoom;
  2501.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2502.                   }
  2503.               } else if( CurToken==TrueTok )
  2504.               {   ReDrawFlag |= RFZoom;
  2505.                   DialValue[3] = 0.5;
  2506.               } else if( !CurToken || (CurToken==FalseTok) )
  2507.               {   ReDrawFlag |= RFZoom;
  2508.                   DialValue[3] = 0.0;
  2509.               } else CommandError(ErrorMsg[ErrSyntax]);
  2510.               /* UpdateScrollBars(); */
  2511.               break;
  2512.  
  2513.     case(RotateTok):  FetchToken();
  2514.               if( CurToken==XTok )
  2515.               {   option = 0;
  2516.               } else if( CurToken==YTok )
  2517.               {   option = 1;
  2518.               } else if( CurToken==ZTok )
  2519.               {   option = 2;
  2520.               } else
  2521.               {   CommandError(ErrorMsg[ErrSyntax]);
  2522.                   break;
  2523.               }
  2524.  
  2525.               FetchToken();
  2526.               if( done=(CurToken=='-') )
  2527.                   FetchToken();
  2528. #ifdef INVERT
  2529.               if( option != 1 )
  2530.                   done = !done;
  2531. #endif
  2532.               if( (CurToken==NumberTok) || (CurToken=='.') )
  2533.               {   if( CurToken==NumberTok )
  2534.                   {   if( *TokenPtr=='.' )
  2535.                   {   TokenPtr++;
  2536.                       FetchFloat(TokenValue,100);
  2537.                   } else TokenValue *= 100;
  2538.                   } else FetchFloat(0,100);
  2539.  
  2540.                   if( TokenValue )
  2541.                   {   if( ReDrawFlag & RFRotate )
  2542.                       PrepareTransform();
  2543.  
  2544.                   ReDrawFlag |= (1<<option);
  2545.                   if( done ) TokenValue = -TokenValue;
  2546.                   DialValue[option] += TokenValue/18000.0;
  2547.  
  2548.                   while( DialValue[option]<-1.0 )
  2549.                       DialValue[option] += 2.0;
  2550.                   while( DialValue[option]>1.0 )
  2551.                       DialValue[option] -= 2.0;
  2552.                   if( Interactive )
  2553.                       UpdateScrollBars();
  2554.                   }
  2555.               } else CommandError(ErrorMsg[ErrNotNum]);
  2556.               break;
  2557.  
  2558.     case(TranslateTok):
  2559.               FetchToken();
  2560.               if( CurToken==XTok )
  2561.               {   option = 4;
  2562.               } else if( CurToken==YTok )
  2563.               {   option = 5;
  2564.               } else if( CurToken==ZTok )
  2565.               {   option = 6;
  2566.               } else
  2567.               {   CommandError(ErrorMsg[ErrSyntax]);
  2568.                   break;
  2569.               }
  2570.  
  2571.               FetchToken();
  2572.               if( done=(CurToken=='-') )
  2573.                   FetchToken();
  2574. #ifdef INVERT
  2575.               if( option == 5 )
  2576.                   done = !done;
  2577. #endif
  2578.  
  2579.               if( (CurToken==NumberTok) || (CurToken=='.') )
  2580.               {   if( CurToken==NumberTok )
  2581.                   {   if( *TokenPtr=='.' )
  2582.                   {   TokenPtr++;
  2583.                       FetchFloat(TokenValue,100);
  2584.                   } else TokenValue *= 100;
  2585.                   } else FetchFloat(0,100);
  2586.  
  2587.                   if( TokenValue<=10000 )
  2588.                   {   ReDrawFlag |= (1<<option);
  2589.                   if( done ) TokenValue = -TokenValue;
  2590.                   DialValue[option] = TokenValue/10000.0;
  2591.                   /* UpdateScrollBars(); */
  2592.                   } else CommandError(ErrorMsg[ErrBigNum]);
  2593.               } else CommandError(ErrorMsg[ErrNotNum]);
  2594.               break;
  2595.  
  2596.     case(StereoTok):  FetchToken();
  2597.               if( !CurToken || (CurToken==TrueTok) )
  2598.               {   ReDrawFlag |= RFRefresh;
  2599.                   SetStereoMode(True);
  2600.               } else if( CurToken==FalseTok )
  2601.               {   ReDrawFlag |= RFRefresh;
  2602.                   SetStereoMode(False);
  2603.               } else CommandError(ErrorMsg[ErrSyntax]);
  2604.               break;
  2605.  
  2606.     case(CentreTok):  FetchToken();
  2607.               if( !CurToken || (CurToken==AllTok) )
  2608.               {   CenX = CenY = CenZ = 0;
  2609.               } else
  2610.                   if( QueryExpr=ParseExpression(0) )
  2611.                   {   if( !CurToken )
  2612.                   {   CentreZoneExpr(QueryExpr);
  2613.                   } else CommandError(ErrorMsg[ErrSyntax]);
  2614.                   DeAllocateExpr(QueryExpr);
  2615.                   }
  2616.               break;
  2617.  
  2618.     case(ResizeTok):  FetchToken();
  2619.               break;
  2620.  
  2621.     case(ResetTok):   for( i=0; i<8; i++ )
  2622.                   DialValue[i] = 0.0;
  2623.               ReDrawFlag |= RFDials;
  2624.               ResetTransform();
  2625.  
  2626.               /* ReDrawFlag |= RFRefresh|RFColour; */
  2627.               /* DisplayMode = 0;                  */
  2628.  
  2629.               if( Interactive )
  2630.                   UpdateScrollBars();
  2631.               break;
  2632.  
  2633.     case('?'):
  2634.     case(HelpTok):    if( !HelpFileName )
  2635.                   InitHelpFile();
  2636.               if( HelpInfo )
  2637.                   FindHelpInfo();
  2638.               CurToken=0;
  2639.               break;
  2640.  
  2641.     case(SetTok):     ExecuteSetCommand();
  2642.               break;
  2643.  
  2644.     case(LabelTok):   FetchToken();
  2645.               if( !CurToken || (CurToken==TrueTok) )
  2646.               {   if( InfoChainCount>1 )
  2647.                   {   DefineLabels("%n%r:%c.%a");
  2648.                   } else if( MainGroupCount>1 )
  2649.                   {   DefineLabels("%n%r.%a");
  2650.                   } else DefineLabels("%e%i");
  2651.               } else if( CurToken==FalseTok )
  2652.               {   DeleteLabels();
  2653.               } else if( CurToken==StringTok )
  2654.               {   DefineLabels(TokenIdent);
  2655.               } else DefineLabels(TokenStart);
  2656.               ReDrawFlag |= RFRefresh;
  2657.               break;
  2658.  
  2659.     case(EchoTok):    FetchToken();
  2660.               if( CommandActive )
  2661.                   WriteChar('\n');
  2662.               CommandActive = False;
  2663.  
  2664.               if( CurToken==StringTok )
  2665.               {   WriteString(TokenIdent);
  2666.               } else if( CurToken )
  2667.                   WriteString(TokenStart);
  2668.               WriteChar('\n');
  2669.               CurToken = 0;
  2670.               break;
  2671.  
  2672.     case(DefineTok):  FetchToken();
  2673.               if( CurToken != IdentTok ) 
  2674.               {   CommandError(ErrorMsg[ErrSetName]);
  2675.                   break;
  2676.               }
  2677.  
  2678.               if( (param = (char*)malloc(TokenLength+1)) )
  2679.               {   for( i=0; i<=TokenLength; i++ )
  2680.                   param[i] = TokenIdent[i];
  2681.  
  2682.                   if( FetchToken() )
  2683.                   {   if( QueryExpr=ParseExpression(0) )
  2684.                   {   done = DefineSetExpr(param,QueryExpr);
  2685.                   } else done = True;
  2686.                   } else done = DefineSetExpr(param,(Expr*)NULL);
  2687.               } else done = False;
  2688.  
  2689.               if( !done )
  2690.                   CommandError(ErrorMsg[ErrBadSet]);
  2691.               break;
  2692.  
  2693.     case(BackgroundTok):
  2694.               FetchToken();
  2695.               if( !CurToken )
  2696.               {   CommandError(ErrorMsg[ErrNoCol]);
  2697.               } else if( ParseColour() )
  2698.               {   ReDrawFlag |= RFColour;
  2699.                   BackR = RVal;
  2700.                   BackG = GVal;
  2701.                   BackB = BVal;
  2702. #ifndef IBMPC
  2703.                   FBClear = False;
  2704. #endif
  2705.               } else if( CurToken )
  2706.                   CommandError(ErrorMsg[ErrColour]);
  2707.               break;
  2708.  
  2709.     case(WriteTok):
  2710.     case(SaveTok):    i = CurToken; /* Save keyword! */
  2711.               if( (FileDepth!=-1) && LineStack[FileDepth] )
  2712.               {   CommandError(ErrorMsg[ErrInScrpt]);
  2713.                   break;
  2714.               }
  2715.  
  2716.               option = FetchToken();
  2717.               if( (option==RasMolTok) || (option==ScriptTok)
  2718.                   || IsMoleculeFormat(option)
  2719.                   || IsImageFormat(option) )
  2720.               {   if( !*TokenPtr || *TokenPtr==' ' )
  2721.                   FetchToken();
  2722.               } else if( i==SaveTok )
  2723.               {   option = PDBTok;
  2724.               } else option = 0;
  2725.  
  2726.               if( !CurToken )
  2727.               {   CommandError(ErrorMsg[ErrFilNam]);
  2728.                   break;
  2729.               } else if( CurToken==StringTok )
  2730.               {      ProcessFileName(TokenIdent);
  2731.               } else ProcessFileName(TokenStart);
  2732.               param = DataFileName;
  2733.               CurToken = 0;
  2734.  
  2735.               if( !IsMoleculeFormat(option) )
  2736.               {   if( ReDrawFlag ) RefreshScreen();
  2737.                   WriteImageFile( param, option );
  2738.  
  2739.               } else switch(option)
  2740.               {   case(PDBTok):     SavePDBMolecule(param); break;
  2741.                   case(XYZTok):     SaveXYZMolecule(param); break;
  2742.                   case(CIFTok):     SaveCIFMolecule(param); break;
  2743.                   case(AlchemyTok): SaveAlchemyMolecule(param);
  2744.                         break;
  2745.               } break;
  2746.  
  2747.     case(SourceTok):
  2748.     case(ScriptTok):  FetchToken();
  2749.               if( FileDepth<STACKSIZE )
  2750.               {   if( !CurToken )
  2751.                   {   CommandError(ErrorMsg[ErrFilNam]);
  2752.                   break;
  2753.                   } else if( CurToken==StringTok )
  2754.                   {      ProcessFileName(TokenIdent);
  2755.                   } else ProcessFileName(TokenStart);
  2756.                   CurToken = 0;
  2757.  
  2758.                   script = fopen(DataFileName,"r");
  2759.                   LoadScriptFile(script,DataFileName);
  2760.               } else CommandError(ErrorMsg[ErrScript]);
  2761.               break;
  2762.  
  2763.     case(PrintTok):   if( !PrintImage() )
  2764.               {   if( CommandActive )
  2765.                   WriteChar('\n');
  2766.                   WriteString("Warning: No suitable printer!\n");
  2767.                   CommandActive = False;
  2768.               }
  2769.               break;
  2770.  
  2771.     case(ClipboardTok):
  2772.               if( !ClipboardImage() )
  2773.               {   if( CommandActive )
  2774.                   WriteChar('\n');
  2775.                   WriteString("Unable to copy to clipboard!\n");
  2776.                   CommandActive = False;
  2777.               }
  2778.               break;
  2779.  
  2780.     case(RenumTok):   FetchToken();
  2781.               if( CurToken )
  2782.               {   if( done = (CurToken=='-') )
  2783.                   FetchToken();
  2784.  
  2785.                   if( CurToken==NumberTok )
  2786.                   {   if( done )
  2787.                   {     RenumberMolecule(-(int)TokenValue);
  2788.                   } else RenumberMolecule((int)TokenValue); 
  2789.                   } else CommandError(ErrorMsg[ErrNotNum]);
  2790.               } else RenumberMolecule(1);
  2791.               break;
  2792.  
  2793.     case(StructureTok):
  2794.               DetermineStructure();
  2795.               break;
  2796.  
  2797.     case(ConnectTok): FetchToken();
  2798.                           if( !CurToken )
  2799.                           {   if( MainAtomCount+HetaAtomCount > 255 )
  2800.                               {   ExecuteConnect(False);
  2801.                               } else ExecuteConnect(True);
  2802.                           } else if( CurToken==TrueTok )
  2803.                           {   ExecuteConnect(True);
  2804.                           } else if( CurToken==FalseTok )
  2805.                           {   ExecuteConnect(False);
  2806.               } else CommandError(ErrorMsg[ErrSyntax]);
  2807.               break;
  2808.  
  2809.     case(ShowTok):    ExecuteShowCommand();
  2810.               break;
  2811.  
  2812.     case(ZapTok):     ZapDatabase();
  2813.               break;
  2814.  
  2815.     case(QuitTok):    return( True );
  2816.     default:          CommandError("Unrecognised command");
  2817.               break;
  2818.     }
  2819.  
  2820.     if( CurToken )
  2821.     if( FetchToken() )
  2822.         CommandError("Warning: Ignoring rest of command");
  2823.     TokenPtr = NULL;
  2824.     return( False );
  2825. }
  2826.  
  2827. #ifdef IBMPC
  2828. /* Avoid Optimizer Warning! */
  2829. #pragma optimize("g",)
  2830. #endif
  2831.  
  2832.  
  2833. int ExecuteIPCCommand( ptr )
  2834.     char __huge *ptr;
  2835. {
  2836.     register char *src,*dst;
  2837.     register int len,depth;
  2838.     register int result;
  2839.     auto char buffer[256];
  2840.  
  2841.     result = 0;
  2842.     FileDepth = 0;
  2843.     *LineStack = 0;
  2844. #ifdef IBMPC
  2845.     *NameStack = "DDE Error";
  2846. #else
  2847.     *NameStack = "IPC Error";
  2848. #endif
  2849.  
  2850.     /* Save command line */
  2851.     src=CurLine;  dst=buffer;
  2852.     while( *dst++ = *src++ );
  2853.    
  2854.     while( *ptr && (*ptr==' ') )
  2855.     ptr++;
  2856.  
  2857.     if( *ptr=='[' )
  2858.     {   depth = 0;
  2859.     while( *ptr++ == '[' )
  2860.     {   dst = CurLine;
  2861.         depth=0;  len=1;
  2862.  
  2863.     
  2864.         do {
  2865.         if( *ptr==']' )
  2866.         {   if( !depth )
  2867.             {   *dst = '\0';
  2868.             ptr++; break;
  2869.             } else depth--;
  2870.         } else if( *ptr=='[' )
  2871.             depth++;
  2872.  
  2873.         if( len<255 )
  2874.         {   *dst++ = *ptr;
  2875.             len++;
  2876.         }
  2877.         } while( *ptr++ );
  2878.  
  2879.         if( len==255 )
  2880.         {   if( CommandActive )
  2881.             WriteChar('\n');
  2882.         WriteString("Warning: Remote command too long!\n");
  2883.         CommandActive = False;
  2884.         } else if( ExecuteCommand() )
  2885.         result = 2;
  2886.  
  2887.         while( *ptr && ((*ptr==' ')||(*ptr==';')) )
  2888.         ptr++;
  2889.     }
  2890.     } else if( *ptr )
  2891.     {   dst = CurLine;
  2892.     len = 0;
  2893.  
  2894.     while( True )
  2895.     {   if( len==255 )
  2896.         {   if( CommandActive )
  2897.             WriteChar('\n');
  2898.         WriteString("Warning: Remote command too long!\n");
  2899.         CommandActive = False;
  2900.         break;
  2901.         }
  2902.  
  2903.         if( !(*dst++ = *ptr++) )
  2904.         {   if( ExecuteCommand() )
  2905.             result = 2;
  2906.         break;
  2907.         } else len++;
  2908.     }
  2909.     }
  2910.  
  2911.     FileDepth = -1;
  2912.     if( CommandActive )
  2913.     {   src=buffer; dst=CurLine;
  2914.     while( *dst++ = *src++ );
  2915.     if( !result ) result = 1;
  2916.     }
  2917.  
  2918.     return( result );
  2919. }
  2920.  
  2921.  
  2922. void InitialiseCommand()
  2923. {
  2924.     MaxHist = MinHist = 1;
  2925.     HistBuff[0] = 0;
  2926.  
  2927.     HelpFileName = NULL;
  2928.     FreeInfo = (void __far*)0;
  2929.     HelpInfo = (void __far*)0;
  2930.  
  2931.     CommandActive = False;
  2932.     SelectCount = 0;
  2933.     TokenPtr = NULL;
  2934.     FileDepth = -1;
  2935. }
  2936.